init
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
#include "ovkCAlgorithmProxy.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CAlgorithmContext final : public TKernelObject<IAlgorithmContext>
|
||||
{
|
||||
public:
|
||||
|
||||
CAlgorithmContext(const IKernelContext& ctx, CAlgorithmProxy& algorithmProxy, const Plugins::IPluginObjectDesc& /*pluginObjectDesc*/)
|
||||
: TKernelObject<IAlgorithmContext>(ctx), m_logManager(ctx.getLogManager()), m_algorithmProxy(algorithmProxy) {}
|
||||
|
||||
~CAlgorithmContext() override { }
|
||||
IConfigurationManager& getConfigurationManager() const override { return getKernelContext().getConfigurationManager(); }
|
||||
IAlgorithmManager& getAlgorithmManager() const override { return getKernelContext().getAlgorithmManager(); }
|
||||
ILogManager& getLogManager() const override { return m_logManager; }
|
||||
IErrorManager& getErrorManager() const override { return getKernelContext().getErrorManager(); }
|
||||
ITypeManager& getTypeManager() const override { return getKernelContext().getTypeManager(); }
|
||||
|
||||
CIdentifier getNextInputParameterIdentifier(const CIdentifier& previous) const override
|
||||
{
|
||||
return m_algorithmProxy.getNextInputParameterIdentifier(previous);
|
||||
}
|
||||
|
||||
IParameter* getInputParameter(const CIdentifier& identifier) override { return m_algorithmProxy.getInputParameter(identifier); }
|
||||
|
||||
CIdentifier getNextOutputParameterIdentifier(const CIdentifier& previous) const override
|
||||
{
|
||||
return m_algorithmProxy.getNextOutputParameterIdentifier(previous);
|
||||
}
|
||||
|
||||
IParameter* getOutputParameter(const CIdentifier& identifier) override { return m_algorithmProxy.getOutputParameter(identifier); }
|
||||
bool isInputTriggerActive(const CIdentifier& identifier) const override { return m_algorithmProxy.isInputTriggerActive(identifier); }
|
||||
|
||||
bool activateOutputTrigger(const CIdentifier& identifier, const bool state) override { return m_algorithmProxy.activateOutputTrigger(identifier, state); }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IAlgorithmContext>, OVK_ClassId_Kernel_Algorithm_AlgorithmContext)
|
||||
|
||||
protected:
|
||||
|
||||
ILogManager& m_logManager;
|
||||
CAlgorithmProxy& m_algorithmProxy;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
#include "ovkCAlgorithmManager.h"
|
||||
#include "ovkCAlgorithmProxy.h"
|
||||
|
||||
#include <system/ovCMath.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CAlgorithmManager::~CAlgorithmManager()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
for (auto& algorithm : m_algorithms)
|
||||
{
|
||||
CAlgorithmProxy* algorithmProxy = algorithm.second;
|
||||
Plugins::IAlgorithm& tmpAlgorithm = algorithmProxy->getAlgorithm();
|
||||
delete algorithmProxy;
|
||||
|
||||
getKernelContext().getPluginManager().releasePluginObject(&tmpAlgorithm);
|
||||
}
|
||||
|
||||
m_algorithms.clear();
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmManager::createAlgorithm(const CIdentifier& algorithmClassID)
|
||||
{
|
||||
const Plugins::IAlgorithmDesc* algorithmDesc = nullptr;
|
||||
Plugins::IAlgorithm* algorithm = getKernelContext().getPluginManager().createAlgorithm(algorithmClassID, &algorithmDesc);
|
||||
|
||||
OV_ERROR_UNLESS_KRU(algorithm && algorithmDesc, "Algorithm creation failed, class identifier :" << algorithmClassID.str(),
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
getLogManager() << LogLevel_Debug << "Creating algorithm with class identifier " << algorithmClassID << "\n";
|
||||
|
||||
CIdentifier algorithmId = getUnusedIdentifier();
|
||||
CAlgorithmProxy* algorithmProxy = new CAlgorithmProxy(getKernelContext(), *algorithm, *algorithmDesc);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
m_algorithms[algorithmId] = algorithmProxy;
|
||||
}
|
||||
|
||||
return algorithmId;
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmManager::createAlgorithm(const Plugins::IAlgorithmDesc& algorithmDesc)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
Plugins::IAlgorithm* algorithm = getKernelContext().getPluginManager().createAlgorithm(algorithmDesc);
|
||||
|
||||
OV_ERROR_UNLESS_KRU(algorithm, "Algorithm creation failed, class identifier :" << algorithmDesc.getClassIdentifier().str(),
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
getLogManager() << LogLevel_Debug << "Creating algorithm with class identifier " << algorithmDesc.getClassIdentifier() << "\n";
|
||||
|
||||
CIdentifier algorithmId = getUnusedIdentifier();
|
||||
CAlgorithmProxy* algorithmProxy = new CAlgorithmProxy(getKernelContext(), *algorithm, algorithmDesc);
|
||||
m_algorithms[algorithmId] = algorithmProxy;
|
||||
return algorithmId;
|
||||
}
|
||||
|
||||
|
||||
bool CAlgorithmManager::releaseAlgorithm(const CIdentifier& rAlgorithmIdentifier)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
const auto itAlgorithm = m_algorithms.find(rAlgorithmIdentifier);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(itAlgorithm != m_algorithms.end(),
|
||||
"Algorithm release failed, identifier :" << rAlgorithmIdentifier.str(),
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
getLogManager() << LogLevel_Debug << "Releasing algorithm with identifier " << rAlgorithmIdentifier << "\n";
|
||||
CAlgorithmProxy* algorithmProxy = itAlgorithm->second;
|
||||
if (algorithmProxy)
|
||||
{
|
||||
Plugins::IAlgorithm& algorithm = algorithmProxy->getAlgorithm();
|
||||
|
||||
delete algorithmProxy;
|
||||
algorithmProxy = nullptr;
|
||||
|
||||
getKernelContext().getPluginManager().releasePluginObject(&algorithm);
|
||||
}
|
||||
m_algorithms.erase(itAlgorithm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAlgorithmManager::releaseAlgorithm(IAlgorithmProxy& rAlgorithm)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
bool result = false;
|
||||
for (auto& algorithm : m_algorithms)
|
||||
{
|
||||
CAlgorithmProxy* algorithmProxy = algorithm.second;
|
||||
if (algorithmProxy == &rAlgorithm)
|
||||
{
|
||||
Plugins::IAlgorithm& tmpAlgorithm = algorithmProxy->getAlgorithm();
|
||||
getLogManager() << LogLevel_Debug << "Releasing algorithm with class id " << tmpAlgorithm.getClassIdentifier() << "\n";
|
||||
|
||||
delete algorithmProxy;
|
||||
algorithmProxy = nullptr;
|
||||
|
||||
m_algorithms.erase(algorithm.first);
|
||||
getKernelContext().getPluginManager().releasePluginObject(&tmpAlgorithm);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_KRF(result, "Algorithm release failed", Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
IAlgorithmProxy& CAlgorithmManager::getAlgorithm(const CIdentifier& rAlgorithmIdentifier)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
const auto itAlgorithm = m_algorithms.find(rAlgorithmIdentifier);
|
||||
|
||||
OV_FATAL_UNLESS_K(itAlgorithm != m_algorithms.end(), "Algorithm " << rAlgorithmIdentifier << " does not exist !", Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
return *itAlgorithm->second;
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmManager::getNextAlgorithmIdentifier(const CIdentifier& previousID) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
auto itAlgorithm = m_algorithms.begin();
|
||||
if (previousID != CIdentifier::undefined())
|
||||
{
|
||||
itAlgorithm = m_algorithms.find(previousID);
|
||||
if (itAlgorithm == m_algorithms.end()) { return CIdentifier::undefined(); }
|
||||
++itAlgorithm;
|
||||
}
|
||||
return (itAlgorithm != m_algorithms.end() ? itAlgorithm->first : CIdentifier::undefined());
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmManager::getUnusedIdentifier() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
uint64_t identifier = CIdentifier::random().id();
|
||||
CIdentifier result;
|
||||
|
||||
std::map<CIdentifier, CAlgorithmProxy*>::const_iterator i;
|
||||
do
|
||||
{
|
||||
identifier++;
|
||||
result = CIdentifier(identifier);
|
||||
i = m_algorithms.find(result);
|
||||
} while (i != m_algorithms.end() || result == CIdentifier::undefined());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CAlgorithmProxy;
|
||||
|
||||
class CAlgorithmManager final : public TKernelObject<IAlgorithmManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CAlgorithmManager(const IKernelContext& ctx) : TKernelObject<IAlgorithmManager>(ctx) {}
|
||||
~CAlgorithmManager() override;
|
||||
CIdentifier createAlgorithm(const CIdentifier& algorithmClassID) override;
|
||||
CIdentifier createAlgorithm(const Plugins::IAlgorithmDesc& algorithmDesc) override;
|
||||
bool releaseAlgorithm(const CIdentifier& rAlgorithmIdentifier) override;
|
||||
bool releaseAlgorithm(IAlgorithmProxy& rAlgorithm) override;
|
||||
IAlgorithmProxy& getAlgorithm(const CIdentifier& rAlgorithmIdentifier) override;
|
||||
CIdentifier getNextAlgorithmIdentifier(const CIdentifier& previousID) const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IAlgorithmManager>, OVK_ClassId_Kernel_Algorithm_AlgorithmManager)
|
||||
|
||||
protected:
|
||||
|
||||
CIdentifier getUnusedIdentifier() const;
|
||||
std::map<CIdentifier, CAlgorithmProxy*> m_algorithms;
|
||||
mutable std::mutex m_oMutex;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "ovkCAlgorithmProto.h"
|
||||
#include "ovkCAlgorithmProxy.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CAlgorithmProto::CAlgorithmProto(const IKernelContext& ctx, CAlgorithmProxy& rAlgorithmProxy)
|
||||
: TKernelObject<IAlgorithmProto>(ctx), m_algorithmProxy(rAlgorithmProxy) {}
|
||||
|
||||
bool CAlgorithmProto::addInputParameter(const CIdentifier& inputParameterID, const CString& sInputName,
|
||||
const EParameterType eParameterType, const CIdentifier& subTypeID)
|
||||
{
|
||||
return m_algorithmProxy.addInputParameter(inputParameterID, sInputName, eParameterType, subTypeID);
|
||||
}
|
||||
|
||||
bool CAlgorithmProto::addOutputParameter(const CIdentifier& outputParameterID, const CString& sOutputName,
|
||||
const EParameterType eParameterType, const CIdentifier& subTypeID)
|
||||
{
|
||||
return m_algorithmProxy.addOutputParameter(outputParameterID, sOutputName, eParameterType, subTypeID);
|
||||
}
|
||||
|
||||
bool CAlgorithmProto::addInputTrigger(const CIdentifier& inputTriggerID, const CString& rInputTriggerName)
|
||||
{
|
||||
return m_algorithmProxy.addInputTrigger(inputTriggerID, rInputTriggerName);
|
||||
}
|
||||
|
||||
bool CAlgorithmProto::addOutputTrigger(const CIdentifier& outputTriggerID, const CString& rOutputTriggerName)
|
||||
{
|
||||
return m_algorithmProxy.addOutputTrigger(outputTriggerID, rOutputTriggerName);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CAlgorithmProxy;
|
||||
|
||||
class CAlgorithmProto final : public TKernelObject<IAlgorithmProto>
|
||||
{
|
||||
public:
|
||||
|
||||
CAlgorithmProto(const IKernelContext& ctx, CAlgorithmProxy& rAlgorithmProxy);
|
||||
bool addInputParameter(const CIdentifier& inputParameterID, const CString& sInputName, EParameterType eParameterType,
|
||||
const CIdentifier& subTypeID) override;
|
||||
bool addOutputParameter(const CIdentifier& outputParameterID, const CString& sOutputName, EParameterType eParameterType,
|
||||
const CIdentifier& subTypeID) override;
|
||||
bool addInputTrigger(const CIdentifier& inputTriggerID, const CString& rInputTriggerName) override;
|
||||
bool addOutputTrigger(const CIdentifier& outputTriggerID, const CString& rOutputTriggerName) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IAlgorithmProto>, OVK_ClassId_Kernel_Algorithm_AlgorithmProto)
|
||||
|
||||
protected:
|
||||
|
||||
CAlgorithmProxy& m_algorithmProxy;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,285 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "ovkCAlgorithmProxy.h"
|
||||
#include "ovkCAlgorithmContext.h"
|
||||
#include "ovkCAlgorithmProto.h"
|
||||
|
||||
#include "../../ovk_tools.h"
|
||||
|
||||
#include <openvibe/ovExceptionHandler.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CAlgorithmProxy::CAlgorithmProxy(const IKernelContext& ctx, Plugins::IAlgorithm& rAlgorithm, const Plugins::IAlgorithmDesc& algorithmDesc)
|
||||
: TKernelObject<IAlgorithmProxy>(ctx), m_algorithmDesc(algorithmDesc), m_algorithm(rAlgorithm)
|
||||
{
|
||||
m_iConfigurable = dynamic_cast<IConfigurable*>(getKernelContext().getKernelObjectFactory().createObject(OV_ClassId_Kernel_Configurable));
|
||||
m_oConfigurable = dynamic_cast<IConfigurable*>(getKernelContext().getKernelObjectFactory().createObject(OV_ClassId_Kernel_Configurable));
|
||||
|
||||
// FIXME
|
||||
CAlgorithmProto algorithmProto(ctx, *this);
|
||||
algorithmDesc.getAlgorithmPrototype(algorithmProto);
|
||||
}
|
||||
|
||||
CAlgorithmProxy::~CAlgorithmProxy()
|
||||
{
|
||||
getKernelContext().getKernelObjectFactory().releaseObject(m_oConfigurable);
|
||||
getKernelContext().getKernelObjectFactory().releaseObject(m_iConfigurable);
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::addInputParameter(const CIdentifier& parameterID, const CString& name, const EParameterType parameterType,
|
||||
const CIdentifier& subTypeID)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_iConfigurable->getParameter(parameterID) == nullptr,
|
||||
"For algorithm " << m_algorithmDesc.getName() << " : Input parameter id " << parameterID.str() << " already exists",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
m_iConfigurable->createParameter(parameterID, parameterType, subTypeID);
|
||||
m_iParameterNames[parameterID] = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmProxy::getNextInputParameterIdentifier(const CIdentifier& parameterID) const
|
||||
{
|
||||
return m_iConfigurable->getNextParameterIdentifier(parameterID);
|
||||
}
|
||||
|
||||
IParameter* CAlgorithmProxy::getInputParameter(const CIdentifier& parameterID)
|
||||
{
|
||||
IParameter* parameter = m_iConfigurable->getParameter(parameterID);
|
||||
|
||||
OV_ERROR_UNLESS_KRN(
|
||||
parameter, "For algorithm " << m_algorithmDesc.getName() << " : Requested null input parameter id " << parameterID.str(),
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
EParameterType CAlgorithmProxy::getInputParameterType(const CIdentifier& parameterID) const
|
||||
{
|
||||
IParameter* parameter = m_iConfigurable->getParameter(parameterID);
|
||||
if (!parameter) { return ParameterType_None; }
|
||||
return parameter->getType();
|
||||
}
|
||||
|
||||
CString CAlgorithmProxy::getInputParameterName(const CIdentifier& parameterID) const
|
||||
{
|
||||
const auto itName = m_iParameterNames.find(parameterID);
|
||||
if (itName == m_iParameterNames.end()) { return ""; }
|
||||
return itName->second;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::removeInputParameter(const CIdentifier& parameterID)
|
||||
{
|
||||
if (!m_iConfigurable->removeParameter(parameterID)) { return false; }
|
||||
m_iParameterNames.erase(m_iParameterNames.find(parameterID));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::addOutputParameter(const CIdentifier& parameterID, const CString& name, const EParameterType parameterType,
|
||||
const CIdentifier& subTypeID)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_oConfigurable->getParameter(parameterID) == nullptr,
|
||||
"For algorithm " << m_algorithmDesc.getName() << " : Output parameter id " << parameterID.str() <<
|
||||
" already exists",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
m_oConfigurable->createParameter(parameterID, parameterType, subTypeID);
|
||||
m_oParameterNames[parameterID] = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmProxy::getNextOutputParameterIdentifier(const CIdentifier& parameterID) const
|
||||
{
|
||||
return m_oConfigurable->getNextParameterIdentifier(parameterID);
|
||||
}
|
||||
|
||||
IParameter* CAlgorithmProxy::getOutputParameter(const CIdentifier& parameterID)
|
||||
{
|
||||
IParameter* parameter = m_oConfigurable->getParameter(parameterID);
|
||||
|
||||
OV_ERROR_UNLESS_KRN(
|
||||
parameter, "For algorithm " << m_algorithmDesc.getName() << " : Requested null output parameter id " << parameterID.str(),
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
EParameterType CAlgorithmProxy::getOutputParameterType(const CIdentifier& parameterID) const
|
||||
{
|
||||
IParameter* parameter = m_oConfigurable->getParameter(parameterID);
|
||||
if (!parameter) { return ParameterType_None; }
|
||||
return parameter->getType();
|
||||
}
|
||||
|
||||
CString CAlgorithmProxy::getOutputParameterName(const CIdentifier& parameterID) const
|
||||
{
|
||||
const auto itName = m_oParameterNames.find(parameterID);
|
||||
if (itName == m_oParameterNames.end()) { return ""; }
|
||||
return itName->second;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::removeOutputParameter(const CIdentifier& parameterID)
|
||||
{
|
||||
if (!m_oConfigurable->removeParameter(parameterID)) { return false; }
|
||||
m_oParameterNames.erase(m_oParameterNames.find(parameterID));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::addInputTrigger(const CIdentifier& triggerID, const CString& name)
|
||||
{
|
||||
if (m_iTriggers.find(triggerID) != m_iTriggers.end()) { return false; }
|
||||
m_iTriggers[triggerID].first = name;
|
||||
m_iTriggers[triggerID].second = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmProxy::getNextInputTriggerIdentifier(const CIdentifier& triggerID) const
|
||||
{
|
||||
return getNextIdentifier<std::pair<CString, bool>>(m_iTriggers, triggerID);
|
||||
}
|
||||
|
||||
CString CAlgorithmProxy::getInputTriggerName(const CIdentifier& triggerID) const
|
||||
{
|
||||
const auto itTrigger = m_iTriggers.find(triggerID);
|
||||
if (itTrigger == m_iTriggers.end()) { return ""; }
|
||||
return itTrigger->second.first;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::isInputTriggerActive(const CIdentifier& triggerID) const
|
||||
{
|
||||
const auto itTrigger = m_iTriggers.find(triggerID);
|
||||
if (itTrigger == m_iTriggers.end()) { return false; }
|
||||
return itTrigger->second.second;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::activateInputTrigger(const CIdentifier& triggerID, const bool /*triggerState*/)
|
||||
{
|
||||
const auto itTrigger = m_iTriggers.find(triggerID);
|
||||
if (itTrigger == m_iTriggers.end()) { return false; }
|
||||
itTrigger->second.second = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::removeInputTrigger(const CIdentifier& triggerID)
|
||||
{
|
||||
const auto itTrigger = m_iTriggers.find(triggerID);
|
||||
if (itTrigger == m_iTriggers.end()) { return false; }
|
||||
m_iTriggers.erase(itTrigger);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::addOutputTrigger(const CIdentifier& triggerID, const CString& name)
|
||||
{
|
||||
if (m_oTriggers.find(triggerID) != m_oTriggers.end()) { return false; }
|
||||
m_oTriggers[triggerID].first = name;
|
||||
m_oTriggers[triggerID].second = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CAlgorithmProxy::getNextOutputTriggerIdentifier(const CIdentifier& triggerID) const
|
||||
{
|
||||
return getNextIdentifier<std::pair<CString, bool>>(m_oTriggers, triggerID);
|
||||
}
|
||||
|
||||
CString CAlgorithmProxy::getOutputTriggerName(const CIdentifier& triggerID) const
|
||||
{
|
||||
const auto itTrigger = m_oTriggers.find(triggerID);
|
||||
if (itTrigger == m_oTriggers.end()) { return ""; }
|
||||
return itTrigger->second.first;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::isOutputTriggerActive(const CIdentifier& triggerID) const
|
||||
{
|
||||
const auto itTrigger = m_oTriggers.find(triggerID);
|
||||
if (itTrigger == m_oTriggers.end()) { return false; }
|
||||
return itTrigger->second.second;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::activateOutputTrigger(const CIdentifier& triggerID, const bool /*state*/)
|
||||
{
|
||||
const auto itTrigger = m_oTriggers.find(triggerID);
|
||||
if (itTrigger == m_oTriggers.end()) { return false; }
|
||||
itTrigger->second.second = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::removeOutputTrigger(const CIdentifier& triggerID)
|
||||
{
|
||||
const auto itTrigger = m_oTriggers.find(triggerID);
|
||||
if (itTrigger == m_oTriggers.end()) { return false; }
|
||||
m_oTriggers.erase(itTrigger);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CAlgorithmProxy::initialize()
|
||||
{
|
||||
assert(!m_isInitialized);
|
||||
|
||||
return translateException([&]()
|
||||
{
|
||||
CAlgorithmContext context(getKernelContext(), *this, m_algorithmDesc);
|
||||
// The dual state initialized or not does not take into account
|
||||
// a partially initialized state. Thus, we have to trust algorithms to implement
|
||||
// their initialization routine as a rollback transaction mechanism
|
||||
m_isInitialized = m_algorithm.initialize(context);
|
||||
return m_isInitialized;
|
||||
},
|
||||
std::bind(&CAlgorithmProxy::handleException, this, "Algorithm initialization", std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::uninitialize()
|
||||
{
|
||||
assert(m_isInitialized);
|
||||
|
||||
return translateException([&]()
|
||||
{
|
||||
CAlgorithmContext context(getKernelContext(), *this, m_algorithmDesc);
|
||||
return m_algorithm.uninitialize(context);
|
||||
},
|
||||
std::bind(&CAlgorithmProxy::handleException, this, "Algorithm uninitialization", std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::process()
|
||||
{
|
||||
assert(m_isInitialized);
|
||||
|
||||
return translateException([&]()
|
||||
{
|
||||
CAlgorithmContext context(getKernelContext(), *this, m_algorithmDesc);
|
||||
this->setAllOutputTriggers(false);
|
||||
const bool result = m_algorithm.process(context);
|
||||
this->setAllInputTriggers(false);
|
||||
return result;
|
||||
},
|
||||
std::bind(&CAlgorithmProxy::handleException, this, "Algorithm processing", std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool CAlgorithmProxy::process(const CIdentifier& triggerID)
|
||||
{
|
||||
assert(m_isInitialized);
|
||||
if (!this->activateInputTrigger(triggerID, true)) { return false; }
|
||||
return this->process();
|
||||
}
|
||||
|
||||
void CAlgorithmProxy::setAllInputTriggers(const bool status) { for (auto& trigger : m_iTriggers) { trigger.second.second = status; } }
|
||||
|
||||
void CAlgorithmProxy::setAllOutputTriggers(const bool status) { for (auto& trigger : m_oTriggers) { trigger.second.second = status; } }
|
||||
|
||||
bool CAlgorithmProxy::isAlgorithmDerivedFrom(const CIdentifier& classID) { return m_algorithm.isDerivedFromClass(classID); }
|
||||
|
||||
void CAlgorithmProxy::handleException(const char* errorHint, const std::exception& exception)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Error << "Exception caught in algorithm\n";
|
||||
this->getLogManager() << LogLevel_Error << " [name: " << this->getAlgorithmDesc().getName() << "]\n";
|
||||
this->getLogManager() << LogLevel_Error << " [class identifier: " << this->getAlgorithmDesc().getCreatedClass() << "]\n";
|
||||
this->getLogManager() << LogLevel_Error << " [hint: " << (errorHint ? errorHint : "no hint") << "]\n";
|
||||
this->getLogManager() << LogLevel_Error << " [cause: " << exception.what() << "]\n";
|
||||
|
||||
OV_ERROR_KRV("Caught exception: " << exception.what(), Kernel::ErrorType::ExceptionCaught);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CAlgorithmProxy final : public TKernelObject<IAlgorithmProxy>
|
||||
{
|
||||
public:
|
||||
|
||||
CAlgorithmProxy(const IKernelContext& ctx, Plugins::IAlgorithm& rAlgorithm, const Plugins::IAlgorithmDesc& algorithmDesc);
|
||||
~CAlgorithmProxy() override;
|
||||
|
||||
Plugins::IAlgorithm& getAlgorithm() { return m_algorithm; }
|
||||
const Plugins::IAlgorithm& getAlgorithm() const { return m_algorithm; }
|
||||
const Plugins::IAlgorithmDesc& getAlgorithmDesc() const { return m_algorithmDesc; }
|
||||
|
||||
bool addInputParameter(const CIdentifier& parameterID, const CString& name, EParameterType parameterType, const CIdentifier& subTypeID);
|
||||
CIdentifier getNextInputParameterIdentifier(const CIdentifier& parameterID) const override;
|
||||
IParameter* getInputParameter(const CIdentifier& parameterID) override;
|
||||
EParameterType getInputParameterType(const CIdentifier& parameterID) const;
|
||||
CString getInputParameterName(const CIdentifier& parameterID) const override;
|
||||
bool removeInputParameter(const CIdentifier& parameterID);
|
||||
|
||||
bool addOutputParameter(const CIdentifier& parameterID, const CString& name, EParameterType parameterType, const CIdentifier& subTypeID);
|
||||
CIdentifier getNextOutputParameterIdentifier(const CIdentifier& parameterID) const override;
|
||||
IParameter* getOutputParameter(const CIdentifier& parameterID) override;
|
||||
EParameterType getOutputParameterType(const CIdentifier& parameterID) const;
|
||||
CString getOutputParameterName(const CIdentifier& parameterID) const override;
|
||||
bool removeOutputParameter(const CIdentifier& parameterID);
|
||||
|
||||
bool addInputTrigger(const CIdentifier& triggerID, const CString& name);
|
||||
CIdentifier getNextInputTriggerIdentifier(const CIdentifier& triggerID) const override;
|
||||
CString getInputTriggerName(const CIdentifier& triggerID) const override;
|
||||
bool isInputTriggerActive(const CIdentifier& triggerID) const;
|
||||
bool activateInputTrigger(const CIdentifier& triggerID, bool triggerState) override;
|
||||
bool removeInputTrigger(const CIdentifier& triggerID);
|
||||
|
||||
bool addOutputTrigger(const CIdentifier& triggerID, const CString& name);
|
||||
CIdentifier getNextOutputTriggerIdentifier(const CIdentifier& triggerID) const override;
|
||||
CString getOutputTriggerName(const CIdentifier& triggerID) const override;
|
||||
bool isOutputTriggerActive(const CIdentifier& triggerID) const override;
|
||||
bool activateOutputTrigger(const CIdentifier& triggerID, const bool triggerState);
|
||||
bool removeOutputTrigger(const CIdentifier& triggerID);
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool process() override;
|
||||
bool process(const CIdentifier& triggerID) override;
|
||||
bool isAlgorithmDerivedFrom(const CIdentifier& classID) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IAlgorithmProxy>, OVK_ClassId_Kernel_Algorithm_AlgorithmProxy)
|
||||
|
||||
protected:
|
||||
|
||||
IConfigurable* m_iConfigurable = nullptr;
|
||||
IConfigurable* m_oConfigurable = nullptr;
|
||||
std::map<CIdentifier, CString> m_iParameterNames;
|
||||
std::map<CIdentifier, CString> m_oParameterNames;
|
||||
std::map<CIdentifier, std::pair<CString, bool>> m_iTriggers;
|
||||
std::map<CIdentifier, std::pair<CString, bool>> m_oTriggers;
|
||||
|
||||
void setAllInputTriggers(bool status);
|
||||
void setAllOutputTriggers(bool status);
|
||||
|
||||
private:
|
||||
|
||||
void handleException(const char* errorHint, const std::exception& exception);
|
||||
|
||||
const Plugins::IAlgorithmDesc& m_algorithmDesc;
|
||||
Plugins::IAlgorithm& m_algorithm;
|
||||
bool m_isInitialized = false;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
Executable
+744
@@ -0,0 +1,744 @@
|
||||
#include "ovkCConfigurationManager.h"
|
||||
|
||||
#include <openvibe/kernel/configuration/ovIConfigurationKeywordExpandCallback.h>
|
||||
|
||||
#include <fs/IEntryEnumerator.h>
|
||||
#include <fs/Files.h>
|
||||
|
||||
#include <system/ovCTime.h>
|
||||
#include <system/ovCMath.h>
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
#include <unistd.h> // for getpid
|
||||
#elif defined TARGET_OS_Windows
|
||||
#include <windows.h> // for GetCurrentProcessId
|
||||
#else
|
||||
#endif
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
// because std::tolower has multiple signatures,
|
||||
// it can not be easily used in std::transform
|
||||
// this workaround is taken from http://www.gcek.net/ref/books/sw/cpp/ticppv2/
|
||||
template <class TCharT>
|
||||
static TCharT ToLower(TCharT c) { return std::tolower(c); }
|
||||
|
||||
class CConfigurationManagerEntryEnumeratorCallBack final : public FS::IEntryEnumeratorCallBack
|
||||
{
|
||||
public:
|
||||
|
||||
CConfigurationManagerEntryEnumeratorCallBack(ILogManager& logManager, IErrorManager& errorManager, IConfigurationManager& configManger)
|
||||
: m_logManager(logManager), m_errorManager(errorManager), m_configManager(configManger) { }
|
||||
|
||||
static std::string reduce(const std::string& value)
|
||||
{
|
||||
if (value.length() == 0) { return ""; }
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = value.length() - 1;
|
||||
|
||||
while (i < value.length() && (value[i] == '\t' || value[i] == ' ')) { i++; }
|
||||
while (j >= i && (value[j] == '\t' || value[j] == ' ')) { j--; }
|
||||
|
||||
return value.substr(i, j - i + 1);
|
||||
}
|
||||
|
||||
bool callback(FS::IEntryEnumerator::IEntry& rEntry, FS::IEntryEnumerator::IAttributes& /*attributes*/) override
|
||||
{
|
||||
std::ifstream file;
|
||||
FS::Files::openIFStream(file, rEntry.getName());
|
||||
|
||||
OV_ERROR_UNLESS(file.good(), "Could not open file " << rEntry.getName(), Kernel::ErrorType::ResourceNotFound, false, m_errorManager, m_logManager);
|
||||
m_logManager << LogLevel_Trace << "Processing configuration file " << rEntry.getName() << "\n";
|
||||
|
||||
do
|
||||
{
|
||||
std::string line;
|
||||
std::string linePart;
|
||||
size_t eq;
|
||||
|
||||
while (!file.eof() && (line.length() == 0 || line[line.length() - 1] == '\\'))
|
||||
{
|
||||
while (line.length() != 0 && line[line.length() - 1] == '\\')
|
||||
{
|
||||
line.resize(line.length() - 1); // removes ending backslashes
|
||||
}
|
||||
|
||||
std::getline(file, linePart, '\n');
|
||||
line += reduce(linePart);
|
||||
}
|
||||
|
||||
// process everything except empty line or comment
|
||||
if (!line.empty() && line[0] != '\0' && line[0] != '#')
|
||||
{
|
||||
OV_ERROR_UNLESS((eq=line.find('=')) != std::string::npos,
|
||||
"Invalid syntax in configuration file " << CString(rEntry.getName()) << " : " << line,
|
||||
ErrorType::BadFileParsing, false, m_errorManager, m_logManager);
|
||||
|
||||
std::string name(reduce(line.substr(0, eq)));
|
||||
std::string value(reduce(line.substr(eq + 1, line.length() - eq)));
|
||||
if (name == "Include")
|
||||
{
|
||||
CString wildCard = m_configManager.expand(value.c_str());
|
||||
m_logManager << LogLevel_Trace << "Including configuration file " << wildCard << "...\n";
|
||||
m_configManager.addConfigurationFromFile(wildCard);
|
||||
m_logManager << LogLevel_Trace << "Including configuration file " << wildCard << " done...\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
CIdentifier tokenID = m_configManager.lookUpConfigurationTokenIdentifier(name.c_str());
|
||||
if (tokenID == CIdentifier::undefined())
|
||||
{
|
||||
m_logManager << LogLevel_Trace << "Adding configuration token " << name << " : " << value << "\n";
|
||||
m_configManager.createConfigurationToken(name.c_str(), value.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_logManager << LogLevel_Trace << "Changing configuration token " << name << " to " << value << "\n";
|
||||
|
||||
// warning if base token are overwritten here
|
||||
OV_WARNING_UNLESS(name != "Path_UserData" && name != "Path_Log" && name != "Path_Tmp"
|
||||
&& name != "Path_Lib" && name != "Path_Bin" && name != "OperatingSystem",
|
||||
"Overwriting critical token " + name, m_logManager);
|
||||
|
||||
m_configManager.setConfigurationTokenValue(tokenID, value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!file.eof());
|
||||
|
||||
m_logManager << LogLevel_Trace << "Processing configuration file " << CString(rEntry.getName()) << " finished\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
ILogManager& m_logManager;
|
||||
IErrorManager& m_errorManager;
|
||||
IConfigurationManager& m_configManager;
|
||||
};
|
||||
|
||||
CConfigurationManager::CConfigurationManager(const IKernelContext& ctx, IConfigurationManager* parentConfigManager)
|
||||
: TKernelObject<IConfigurationManager>(ctx), m_parentConfigManager(parentConfigManager)
|
||||
{
|
||||
m_idx = 0;
|
||||
m_startTime = System::Time::getTime();
|
||||
}
|
||||
|
||||
void CConfigurationManager::clear()
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
m_ConfigTokens.clear();
|
||||
}
|
||||
|
||||
bool CConfigurationManager::addConfigurationFromFile(const CString& rFileNameWildCard)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
this->getLogManager() << LogLevel_Trace << "Adding configuration file(s) [" << rFileNameWildCard << "]\n";
|
||||
|
||||
|
||||
CConfigurationManagerEntryEnumeratorCallBack cb(getKernelContext().getLogManager(), getKernelContext().getErrorManager(), *this);
|
||||
FS::IEntryEnumerator* entryEnumerator = createEntryEnumerator(cb);
|
||||
const bool res = entryEnumerator->enumerate(rFileNameWildCard);
|
||||
entryEnumerator->release();
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
CIdentifier CConfigurationManager::createConfigurationToken(const CString& name, const CString& value)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(this->lookUpConfigurationTokenIdentifier(name, false) == CIdentifier::undefined(),
|
||||
"Configuration token name " << name << " already exists", Kernel::ErrorType::BadResourceCreation);
|
||||
|
||||
CIdentifier id = this->getUnusedIdentifier();
|
||||
m_ConfigTokens[id].name = name;
|
||||
m_ConfigTokens[id].value = value;
|
||||
return id;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::releaseConfigurationToken(const CIdentifier& identifier)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_ConfigTokens.find(identifier);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(it != m_ConfigTokens.end(), "Configuration token not found " << identifier.str(), Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
m_ConfigTokens.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CConfigurationManager::getNextConfigurationTokenIdentifier(const CIdentifier& prevConfigTokenID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
std::map<CIdentifier, config_token_t>::const_iterator it;
|
||||
|
||||
if (prevConfigTokenID == CIdentifier::undefined()) { it = m_ConfigTokens.begin(); }
|
||||
else
|
||||
{
|
||||
it = m_ConfigTokens.find(prevConfigTokenID);
|
||||
if (it == m_ConfigTokens.end()) { return CIdentifier::undefined(); }
|
||||
++it;
|
||||
}
|
||||
|
||||
return it != m_ConfigTokens.end() ? it->first : CIdentifier::undefined();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CString CConfigurationManager::getConfigurationTokenName(const CIdentifier& identifier) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_ConfigTokens.find(identifier);
|
||||
if (it != m_ConfigTokens.end()) { return it->second.name; }
|
||||
return "";
|
||||
}
|
||||
|
||||
CString CConfigurationManager::getConfigurationTokenValue(const CIdentifier& identifier) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_ConfigTokens.find(identifier);
|
||||
if (it != m_ConfigTokens.end()) { return it->second.value; }
|
||||
return "";
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool CConfigurationManager::setConfigurationTokenName(const CIdentifier& identifier, const CString& name)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(this->lookUpConfigurationTokenIdentifier(name, false) == CIdentifier::undefined(),
|
||||
"Configuration token name " << name << " already exists", Kernel::ErrorType::BadResourceCreation);
|
||||
|
||||
auto it = m_ConfigTokens.find(identifier);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(it != m_ConfigTokens.end(), "Configuration token " << identifier.str() << " does not exist",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
it->second.name = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::setConfigurationTokenValue(const CIdentifier& identifier, const CString& value)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto itConfigurationToken = m_ConfigTokens.find(identifier);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(itConfigurationToken != m_ConfigTokens.end(), "Configuration token " << identifier.str() << " does not exist",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
itConfigurationToken->second.value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::addOrReplaceConfigurationToken(const CString& name, const CString& value)
|
||||
{
|
||||
const CIdentifier oldID = this->lookUpConfigurationTokenIdentifier(name, false);
|
||||
if (oldID == CIdentifier::undefined()) { return CIdentifier::undefined() != this->createConfigurationToken(name, value); }
|
||||
return this->setConfigurationTokenValue(oldID, value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CIdentifier CConfigurationManager::lookUpConfigurationTokenIdentifier(const CString& name, const bool recursive) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto it = m_ConfigTokens.begin();
|
||||
while (it != m_ConfigTokens.end())
|
||||
{
|
||||
if (it->second.name == name) { return it->first; }
|
||||
++it;
|
||||
}
|
||||
if (recursive && m_parentConfigManager) { return m_parentConfigManager->lookUpConfigurationTokenIdentifier(name, recursive); }
|
||||
return CIdentifier::undefined();
|
||||
}
|
||||
|
||||
CString CConfigurationManager::lookUpConfigurationTokenValue(const CString& name) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto it = m_ConfigTokens.begin();
|
||||
while (it != m_ConfigTokens.end())
|
||||
{
|
||||
if (it->second.name == name) { return it->second.value; }
|
||||
++it;
|
||||
}
|
||||
if (m_parentConfigManager) { return m_parentConfigManager->lookUpConfigurationTokenValue(name); }
|
||||
return "";
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool CConfigurationManager::registerKeywordParser(const CString& keyword, const IConfigurationKeywordExpandCallback& callback)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(keyword != CString("") && keyword != CString("core") && keyword != CString("environment"),
|
||||
"Trying to overwrite internal keyword " << keyword,
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
m_keywordOverrides[keyword] = &callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::unregisterKeywordParser(const CString& keyword)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(m_keywordOverrides.count(keyword), "Override for keyword [" << keyword << "] was not found", Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
m_keywordOverrides.erase(keyword);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::unregisterKeywordParser(const IConfigurationKeywordExpandCallback& callback)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto it = m_keywordOverrides.begin();
|
||||
|
||||
bool res = false;
|
||||
while (it != m_keywordOverrides.end())
|
||||
{
|
||||
if (it->second == &callback)
|
||||
{
|
||||
m_keywordOverrides.erase(it);
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_KRF(res, "Override for the callback was not found", Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CString CConfigurationManager::expand(const CString& expression) const
|
||||
{
|
||||
const std::string value(expression.toASCIIString());
|
||||
std::string res;
|
||||
if (this->internalExpand(value, res)) { return res.c_str(); }
|
||||
return value.c_str();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CIdentifier CConfigurationManager::getUnusedIdentifier() const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
uint64_t id = (uint64_t(rand()) << 32) + uint64_t(rand());
|
||||
CIdentifier res;
|
||||
std::map<CIdentifier, config_token_t>::const_iterator i;
|
||||
do
|
||||
{
|
||||
id++;
|
||||
res = CIdentifier(id);
|
||||
i = m_ConfigTokens.find(res);
|
||||
} while (i != m_ConfigTokens.end() || res == CIdentifier::undefined());
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class ENodeType { Value, NamePrefix, NamePostfix, };
|
||||
|
||||
bool CConfigurationManager::internalExpand(const std::string& sValue, std::string& result) const
|
||||
{
|
||||
std::stack<std::pair<ENodeType, std::string>> children;
|
||||
children.push(std::make_pair(ENodeType::Value, std::string()));
|
||||
|
||||
std::string prefix;
|
||||
std::string postfix;
|
||||
std::string lowerPrefix;
|
||||
std::string lowerPostfix;
|
||||
std::string value;
|
||||
std::string expandedValue;
|
||||
|
||||
for (size_t i = 0; i < sValue.length(); ++i)
|
||||
{
|
||||
bool shouldExpand;
|
||||
|
||||
switch (sValue[i])
|
||||
{
|
||||
case '$':
|
||||
children.push(std::make_pair(ENodeType::NamePrefix, std::string()));
|
||||
break;
|
||||
|
||||
case '{':
|
||||
OV_ERROR_UNLESS_KRF(children.top().first == ENodeType::NamePrefix,
|
||||
"Could not expand token with syntax error while expanding " << sValue, Kernel::ErrorType::BadFileParsing);
|
||||
children.push(std::make_pair(ENodeType::NamePostfix, std::string()));
|
||||
break;
|
||||
|
||||
case '}':
|
||||
OV_ERROR_UNLESS_KRF(children.top().first == ENodeType::NamePostfix,
|
||||
"Could not expand token with syntax error while expanding " << sValue, Kernel::ErrorType::BadFileParsing);
|
||||
postfix = children.top().second;
|
||||
lowerPostfix.resize(postfix.size());
|
||||
std::transform(postfix.begin(), postfix.end(), lowerPostfix.begin(), ToLower<std::string::value_type>);
|
||||
children.pop();
|
||||
|
||||
prefix = children.top().second;
|
||||
lowerPrefix.resize(prefix.size());
|
||||
std::transform(prefix.begin(), prefix.end(), lowerPrefix.begin(), ToLower<std::string::value_type>);
|
||||
children.pop();
|
||||
|
||||
shouldExpand = true;
|
||||
|
||||
if (lowerPrefix.empty())
|
||||
{
|
||||
// value = this->getConfigurationTokenValue(this->lookUpConfigurationTokenIdentifier(postfix.c_str()));
|
||||
// this->internalGetConfigurationTokenValueFromName(postfix, value);
|
||||
value = this->lookUpConfigurationTokenValue(postfix.c_str()).toASCIIString();
|
||||
}
|
||||
else if (lowerPrefix == "environment" || lowerPrefix == "env")
|
||||
{
|
||||
char* envValue = getenv(postfix.c_str());
|
||||
value = (envValue ? envValue : "");
|
||||
shouldExpand = false;
|
||||
}
|
||||
else if (lowerPrefix == "core")
|
||||
{
|
||||
if (lowerPostfix == "random") { value = std::to_string(this->getRandom()); }
|
||||
else if (lowerPostfix == "index") { value = std::to_string(this->getIndex()); }
|
||||
else if (lowerPostfix == "time") { value = this->getTime(); }
|
||||
else if (lowerPostfix == "date") { value = this->getDate(); }
|
||||
else if (lowerPostfix == "real-time") { value = std::to_string(this->getRealTime()); }
|
||||
else if (lowerPostfix == "process-id") { value = std::to_string(this->getProcessId()); }
|
||||
else
|
||||
{
|
||||
OV_ERROR_KRF("Could not expand token with " << prefix << " prefix and " << postfix << " postfix while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_keywordOverrides.count(lowerPrefix.c_str()))
|
||||
{
|
||||
CString overridenValue("");
|
||||
|
||||
OV_ERROR_UNLESS_KRF((m_keywordOverrides.find(lowerPrefix.c_str())->second)->expand(CString(postfix.c_str()), overridenValue),
|
||||
"Could not expand $" << lowerPrefix << "{" << lowerPostfix << "}",
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
value = overridenValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_parentConfigManager, "Could not expand token with " << prefix << " prefix while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
std::string keyword = "$" + lowerPrefix + "{" + lowerPostfix + "}";
|
||||
|
||||
value = m_parentConfigManager->expand(CString(keyword.c_str()));
|
||||
|
||||
if (value == sValue)
|
||||
{
|
||||
value = "";
|
||||
OV_ERROR_KRF("Could not expand token with " << prefix << " prefix while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldExpand)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->internalExpand(value, expandedValue),
|
||||
"Could not expand " << value << " while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
children.top().second += expandedValue;
|
||||
}
|
||||
else { children.top().second += value; }
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
i++;
|
||||
OV_ERROR_UNLESS_KRF(i < sValue.length(),
|
||||
"Could not expand token with unterminated string while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
default:
|
||||
children.top().second += sValue[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This will merge all NamePrefix Node on top of the pile into the first which isn't.
|
||||
* In case of handling an UNC path, pile should look like this, eventually with multiple ENodeType::NamePrefix :
|
||||
* ENodeType::NamePrefix, value2
|
||||
* ENodeType::Value, value1
|
||||
*
|
||||
* This will merge all of them into the Node below, like this :
|
||||
* ENodeType::Value, value1 + '$' + value2 + ( '$' + value3 ...)
|
||||
* Using this method, tokens are not reinterpreted, which reduce risks introduced by introducing parser leniency.
|
||||
*/
|
||||
while (children.top().first == ENodeType::NamePrefix && children.size() > 1)
|
||||
{
|
||||
const std::string topVal = children.top().second;
|
||||
children.pop();
|
||||
children.top().second += "$" + topVal;
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_KRF(children.size() == 1, "Could not expand token with unterminated string while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
result = children.top().second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::internalExpandOnlyKeyword(const std::string& sKeyword, const std::string& sValue, std::string& sResult,
|
||||
bool preserveBackslashes = false) const
|
||||
{
|
||||
std::stack<std::pair<ENodeType, std::string>> childrens;
|
||||
childrens.push(std::make_pair(ENodeType::Value, std::string()));
|
||||
|
||||
std::string prefix;
|
||||
std::string postfix;
|
||||
std::string lowerPrefix;
|
||||
std::string lowerPostfix;
|
||||
std::string value;
|
||||
std::string expandedValue;
|
||||
|
||||
for (size_t i = 0; i < sValue.length(); ++i)
|
||||
{
|
||||
bool shouldExpand;
|
||||
|
||||
switch (sValue[i])
|
||||
{
|
||||
case '$':
|
||||
childrens.push(std::make_pair(ENodeType::NamePrefix, std::string()));
|
||||
break;
|
||||
|
||||
case '{':
|
||||
OV_ERROR_UNLESS_KRF(childrens.top().first == ENodeType::NamePrefix,
|
||||
"Could not expand token with syntax error while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
childrens.push(std::make_pair(ENodeType::NamePostfix, std::string()));
|
||||
break;
|
||||
|
||||
case '}':
|
||||
OV_ERROR_UNLESS_KRF(childrens.top().first == ENodeType::NamePostfix,
|
||||
"Could not expand token with syntax error while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
postfix = childrens.top().second;
|
||||
childrens.pop();
|
||||
|
||||
prefix = childrens.top().second;
|
||||
childrens.pop();
|
||||
|
||||
shouldExpand = true;
|
||||
|
||||
lowerPrefix = prefix;
|
||||
lowerPostfix = postfix;
|
||||
std::transform(lowerPrefix.begin(), lowerPrefix.end(), lowerPrefix.begin(), ToLower<std::string::value_type>);
|
||||
std::transform(lowerPostfix.begin(), lowerPostfix.end(), lowerPostfix.begin(), ToLower<std::string::value_type>);
|
||||
|
||||
if (lowerPrefix == sKeyword)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_keywordOverrides.count(lowerPrefix.c_str()),
|
||||
"Could not expand token with " << prefix << " prefix while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
CString overridenValue("");
|
||||
|
||||
OV_ERROR_UNLESS_KRF((m_keywordOverrides.find(lowerPrefix.c_str())->second)->expand(CString(postfix.c_str()), overridenValue),
|
||||
"Could not expand $" << lowerPrefix << "{" << lowerPostfix << "}",
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
value = overridenValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the previous token was not something we want to parse we will simply put it back
|
||||
value = "$" + prefix + "{" + postfix + "}";
|
||||
shouldExpand = false;
|
||||
}
|
||||
|
||||
if (shouldExpand)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->internalExpandOnlyKeyword(sKeyword, value, expandedValue),
|
||||
"Could not expand " << value << " while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
childrens.top().second += expandedValue;
|
||||
}
|
||||
else { childrens.top().second += value; }
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (preserveBackslashes) { childrens.top().second += sValue[i]; }
|
||||
i++;
|
||||
OV_ERROR_UNLESS_KRF(i < sValue.length(),
|
||||
"Could not expand token with unterminated string while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
childrens.top().second += sValue[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
childrens.top().second += sValue[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_KRF(childrens.size() == 1, "Could not expand token with unterminated string while expanding " << sValue,
|
||||
ErrorType::BadFileParsing);
|
||||
|
||||
sResult = childrens.top().second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::internalGetConfigurationTokenValueFromName(const std::string& name, std::string& value) const
|
||||
{
|
||||
const CIdentifier tokenID = this->lookUpConfigurationTokenIdentifier(name.c_str(), false);
|
||||
if (tokenID == CIdentifier::undefined())
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_parentConfigManager,
|
||||
"Could not expand token [" << name <<
|
||||
"]. This token does not exist. If this is expected behavior, please add \"" << name <<
|
||||
" = \" to your configuration file",
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
const std::string str = std::string("${") + name + ("}");
|
||||
value = m_parentConfigManager->expand(str.c_str());
|
||||
}
|
||||
else { value = this->getConfigurationTokenValue(tokenID); }
|
||||
return true;
|
||||
}
|
||||
|
||||
CString CConfigurationManager::expandOnlyKeyword(const CString& rKeyword, const CString& expression, const bool preserveBackslashes) const
|
||||
{
|
||||
const std::string value(expression.toASCIIString());
|
||||
std::string res;
|
||||
if (this->internalExpandOnlyKeyword(rKeyword.toASCIIString(), value, res, preserveBackslashes)) { return res.c_str(); }
|
||||
return value.c_str();
|
||||
}
|
||||
|
||||
double CConfigurationManager::expandAsFloat(const CString& expression, const double fallbackValue) const
|
||||
{
|
||||
const CString result = this->expand(expression);
|
||||
double res;
|
||||
|
||||
try { res = std::stod(result.toASCIIString()); }
|
||||
catch (const std::exception&) { res = fallbackValue; }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int64_t CConfigurationManager::expandAsInteger(const CString& expression, const int64_t fallbackValue) const
|
||||
{
|
||||
const CString result = this->expand(expression);
|
||||
int64_t res;
|
||||
|
||||
try { res = std::stoll(result.toASCIIString()); }
|
||||
catch (const std::exception&) { res = fallbackValue; }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint64_t CConfigurationManager::expandAsUInteger(const CString& expression, const uint64_t fallbackValue) const
|
||||
{
|
||||
const CString result = this->expand(expression);
|
||||
uint64_t res;
|
||||
|
||||
try { res = std::stoull(result.toASCIIString()); }
|
||||
catch (const std::exception&) { res = fallbackValue; }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CConfigurationManager::expandAsBoolean(const CString& expression, const bool fallbackValue) const
|
||||
{
|
||||
std::string res = this->expand(expression).toASCIIString();
|
||||
std::transform(res.begin(), res.end(), res.begin(), ToLower<std::string::value_type>);
|
||||
|
||||
if (res == "true" || res == "on" || res == "1") { return true; }
|
||||
if (res == "false" || res == "off" || res == "0") { return false; }
|
||||
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
uint64_t CConfigurationManager::expandAsEnumerationEntryValue(const CString& expression, const CIdentifier& enumTypeID, const uint64_t fallbackValue) const
|
||||
{
|
||||
const CString str = this->expand(expression);
|
||||
const uint64_t result = this->getTypeManager().getEnumerationEntryValueFromName(enumTypeID, str);
|
||||
if (result != ULLONG_MAX) { return result; }
|
||||
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
size_t CConfigurationManager::getRandom() { return size_t(System::Math::randomI()); }
|
||||
|
||||
size_t CConfigurationManager::getIndex() const { return m_idx++; }
|
||||
|
||||
CString CConfigurationManager::getTime()
|
||||
{
|
||||
char res[1024];
|
||||
time_t rawTime;
|
||||
|
||||
time(&rawTime);
|
||||
struct tm* timeInfo = localtime(&rawTime);
|
||||
|
||||
sprintf(res, "%02i.%02i.%02i", timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
|
||||
return res;
|
||||
}
|
||||
|
||||
CString CConfigurationManager::getDate()
|
||||
{
|
||||
char res[1024];
|
||||
time_t rawTime;
|
||||
|
||||
time(&rawTime);
|
||||
struct tm* timeInfo = localtime(&rawTime);
|
||||
|
||||
sprintf(res, "%04i.%02i.%02i", timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t CConfigurationManager::getRealTime() const { return System::Time::getTime() - m_startTime; }
|
||||
|
||||
size_t CConfigurationManager::getProcessId()
|
||||
{
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
return size_t(getpid());
|
||||
#elif defined TARGET_OS_Windows
|
||||
return size_t(GetCurrentProcessId());
|
||||
#else
|
||||
#error TODO
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class IConfigurationKeywordExpandCallback;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CString name;
|
||||
CString value;
|
||||
} config_token_t;
|
||||
|
||||
class CConfigurationManager final : public TKernelObject<IConfigurationManager>
|
||||
{
|
||||
public:
|
||||
|
||||
CConfigurationManager(const IKernelContext& ctx, IConfigurationManager* parentConfigManager = nullptr);
|
||||
void clear() override;
|
||||
bool addConfigurationFromFile(const CString& rFileNameWildCard) override;
|
||||
CIdentifier createConfigurationToken(const CString& name, const CString& value) override;
|
||||
bool releaseConfigurationToken(const CIdentifier& identifier) override;
|
||||
CIdentifier getNextConfigurationTokenIdentifier(const CIdentifier& prevConfigTokenID) const override;
|
||||
CString getConfigurationTokenName(const CIdentifier& identifier) const override;
|
||||
CString getConfigurationTokenValue(const CIdentifier& identifier) const override;
|
||||
bool setConfigurationTokenName(const CIdentifier& identifier, const CString& name) override;
|
||||
bool setConfigurationTokenValue(const CIdentifier& identifier, const CString& value) override;
|
||||
bool addOrReplaceConfigurationToken(const CString& name, const CString& value) override;
|
||||
CIdentifier lookUpConfigurationTokenIdentifier(const CString& name, bool recursive) const override;
|
||||
CString lookUpConfigurationTokenValue(const CString& name) const override;
|
||||
bool registerKeywordParser(const CString& keyword, const IConfigurationKeywordExpandCallback& callback) override;
|
||||
bool unregisterKeywordParser(const CString& keyword) override;
|
||||
bool unregisterKeywordParser(const IConfigurationKeywordExpandCallback& callback) override;
|
||||
CString expand(const CString& expression) const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IConfigurationManager>, OVK_ClassId_Kernel_Config_ConfigManager)
|
||||
CString expandOnlyKeyword(const CString& rKeyword, const CString& expression, bool preserveBackslashes) const override;
|
||||
double expandAsFloat(const CString& expression, double fallbackValue) const override;
|
||||
int64_t expandAsInteger(const CString& expression, int64_t fallbackValue) const override;
|
||||
uint64_t expandAsUInteger(const CString& expression, uint64_t fallbackValue) const override;
|
||||
bool expandAsBoolean(const CString& expression, bool fallbackValue) const override;
|
||||
uint64_t expandAsEnumerationEntryValue(const CString& expression, const CIdentifier& enumTypeID, uint64_t fallbackValue) const override;
|
||||
|
||||
protected:
|
||||
|
||||
CIdentifier getUnusedIdentifier() const;
|
||||
|
||||
bool internalExpand(const std::string& sValue, std::string& result) const;
|
||||
bool internalExpandOnlyKeyword(const std::string& sKeyword, const std::string& sValue, std::string& sResult, bool preserveBackslashes) const;
|
||||
bool internalGetConfigurationTokenValueFromName(const std::string& name, std::string& value) const;
|
||||
|
||||
IConfigurationManager* m_parentConfigManager = nullptr;
|
||||
mutable size_t m_idx;
|
||||
mutable size_t m_startTime;
|
||||
|
||||
static size_t getRandom();
|
||||
size_t getIndex() const;
|
||||
static CString getTime();
|
||||
static CString getDate();
|
||||
size_t getRealTime() const;
|
||||
static size_t getProcessId();
|
||||
|
||||
std::map<CIdentifier, config_token_t> m_ConfigTokens;
|
||||
std::map<CString, const IConfigurationKeywordExpandCallback*> m_keywordOverrides;
|
||||
|
||||
mutable std::recursive_mutex m_mutex;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,92 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ovkCErrorManager.h"
|
||||
|
||||
// Error manager IError internal implementation
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CError final : public IError
|
||||
{
|
||||
public:
|
||||
|
||||
CError(ErrorType type, const char* description, IError* nestedError, const char* filename, const size_t line)
|
||||
: m_errorType(type), m_nestedError(nestedError), m_description(description), m_location(std::string(filename) + ":" + std::to_string(line)) { }
|
||||
|
||||
~CError() override { }
|
||||
|
||||
const char* getErrorString() const override { return m_description.c_str(); }
|
||||
const char* getErrorLocation() const override { return m_location.c_str(); }
|
||||
ErrorType getErrorType() const override { return m_errorType; }
|
||||
const IError* getNestedError() const override { return m_nestedError.get(); }
|
||||
|
||||
_IsDerivedFromClass_Final_(IError, OVK_ClassId_Kernel_Error_Error)
|
||||
|
||||
private:
|
||||
|
||||
ErrorType m_errorType;
|
||||
std::unique_ptr<IError> m_nestedError;
|
||||
std::string m_description;
|
||||
std::string m_location;
|
||||
};
|
||||
|
||||
// Error manager implementation
|
||||
void CErrorManager::pushErrorAtLocation(const ErrorType type, const char* description, const char* filename, const size_t line)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_managerGuard);
|
||||
const auto lastTopError = m_topError.release();
|
||||
m_topError.reset(new CError(type, description, lastTopError, filename, line));
|
||||
}
|
||||
|
||||
void CErrorManager::releaseErrors()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_managerGuard);
|
||||
m_topError.reset(nullptr);
|
||||
}
|
||||
|
||||
bool CErrorManager::hasError() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_managerGuard);
|
||||
return (m_topError != nullptr);
|
||||
}
|
||||
|
||||
const IError* CErrorManager::getLastError() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_managerGuard);
|
||||
return m_topError.get();
|
||||
}
|
||||
|
||||
const char* CErrorManager::getLastErrorString() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_managerGuard);
|
||||
return (m_topError ? m_topError->getErrorString() : "");
|
||||
}
|
||||
|
||||
ErrorType CErrorManager::getLastErrorType() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_managerGuard);
|
||||
return (m_topError ? m_topError->getErrorType() : ErrorType::NoErrorFound);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
/**
|
||||
* \class CErrorManager
|
||||
* \author Charles Garraud (Inria)
|
||||
* \date 2016-07-13
|
||||
* \brief Error manager kernel default implementation
|
||||
*/
|
||||
class CErrorManager final : public TKernelObject<IErrorManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CErrorManager(const IKernelContext& context) : TKernelObject<IErrorManager>(context), m_topError(nullptr) { }
|
||||
~CErrorManager() override { this->releaseErrors(); }
|
||||
|
||||
void pushError(ErrorType type, const char* description) override { this->pushErrorAtLocation(type, description, "NoLocationInfo", 0); }
|
||||
void pushErrorAtLocation(ErrorType type, const char* description, const char* filename, size_t line) override;
|
||||
void releaseErrors() override;
|
||||
bool hasError() const override;
|
||||
const IError* getLastError() const override;
|
||||
const char* getLastErrorString() const override;
|
||||
ErrorType getLastErrorType() const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IErrorManager>, OVK_ClassId_Kernel_Error_ErrorManager)
|
||||
|
||||
private:
|
||||
|
||||
mutable std::mutex m_managerGuard;
|
||||
std::unique_ptr<IError> m_topError;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+409
@@ -0,0 +1,409 @@
|
||||
#include "ovkCLogListenerConsole.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CLogListenerConsole::CLogListenerConsole(const IKernelContext& ctx, const CString& sApplicationName)
|
||||
: TKernelObject<ILogListener>(ctx), m_color(LogColor_Default), m_applicationName(sApplicationName), m_timeInSeconds(true), m_timePrecision(3),
|
||||
m_useColor(true)
|
||||
{
|
||||
#if defined TARGET_OS_Windows
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CLogListenerConsole::configure(const IConfigurationManager& configManager)
|
||||
{
|
||||
m_timeInSeconds = configManager.expandAsBoolean("${Kernel_ConsoleLogTimeInSecond}", true);
|
||||
m_logWithHexa = configManager.expandAsBoolean("${Kernel_ConsoleLogWithHexa}", false);
|
||||
m_timePrecision = configManager.expandAsUInteger("${Kernel_ConsoleLogTimePrecision}", 3);
|
||||
m_useColor = configManager.expandAsBoolean("${Kernel_ConsoleLogUseColor}", true);
|
||||
}
|
||||
|
||||
|
||||
bool CLogListenerConsole::isActive(const ELogLevel level)
|
||||
{
|
||||
const auto itLogLevel = m_activeLevels.find(level);
|
||||
if (itLogLevel == m_activeLevels.end()) { return true; }
|
||||
return itLogLevel->second;
|
||||
}
|
||||
|
||||
bool CLogListenerConsole::activate(const ELogLevel level, const bool active)
|
||||
{
|
||||
m_activeLevels[level] = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogListenerConsole::activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active)
|
||||
{
|
||||
for (int i = startLevel; i <= endLevel; ++i) { m_activeLevels[ELogLevel(i)] = active; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogListenerConsole::activate(const bool active) { return activate(LogLevel_First, LogLevel_Last, active); }
|
||||
|
||||
void CLogListenerConsole::log(const CTime value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
std::cout << value.str(m_timeInSeconds, m_logWithHexa);
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const uint64_t value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
const std::ios_base::fmtflags fmt = std::cout.flags();
|
||||
std::cout << std::dec << value;
|
||||
if (m_logWithHexa) { std::cout << " (0x" << std::hex << value << ")"; }
|
||||
|
||||
std::cout.flags(fmt);
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const uint32_t value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
const std::ios_base::fmtflags fmt = std::cout.flags();
|
||||
std::cout << std::dec << value;
|
||||
if (m_logWithHexa) { std::cout << " (0x" << std::hex << value << ")"; }
|
||||
std::cout.flags(fmt);
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const int64_t value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
const std::ios_base::fmtflags fmt = std::cout.flags();
|
||||
std::cout << std::dec << value;
|
||||
if (m_logWithHexa) { std::cout << " (0x" << std::hex << value << ")"; }
|
||||
std::cout.flags(fmt);
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const int value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
const std::ios_base::fmtflags fmt = std::cout.flags();
|
||||
std::cout << std::dec << value;
|
||||
if (m_logWithHexa) { std::cout << " (0x" << std::hex << value << ")"; }
|
||||
std::cout.flags(fmt);
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const double value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
std::cout << value;
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const bool value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
std::cout << (value ? "true" : "false");
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const CIdentifier& value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
std::cout << value.str();
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const CString& value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
std::cout << value;
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const std::string& value)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
this->log(LogColor_ForegroundMagenta);
|
||||
std::cout << value;
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const char* value) { std::cout << value << std::flush; }
|
||||
|
||||
void CLogListenerConsole::log(const ELogLevel level)
|
||||
{
|
||||
this->log(LogColor_PushStateBit);
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel_Debug: this->log(LogColor_ForegroundBlue);
|
||||
break;
|
||||
case LogLevel_Benchmark: this->log(LogColor_ForegroundMagenta);
|
||||
break;
|
||||
case LogLevel_Trace: this->log(LogColor_ForegroundYellow);
|
||||
break;
|
||||
case LogLevel_Info: this->log(LogColor_ForegroundGreen);
|
||||
break;
|
||||
case LogLevel_Warning: this->log(LogColor_ForegroundCyan);
|
||||
break;
|
||||
case LogLevel_ImportantWarning:
|
||||
case LogLevel_Error:
|
||||
case LogLevel_Fatal: this->log(LogColor_ForegroundRed);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
std::cout << toString(level);
|
||||
this->log(LogColor_PopStateBit);
|
||||
}
|
||||
|
||||
void CLogListenerConsole::log(const ELogColor color)
|
||||
{
|
||||
if (m_useColor)
|
||||
{
|
||||
// Tests 'push state' bit
|
||||
if (color & LogColor_PushStateBit) { m_colors.push(m_color); }
|
||||
|
||||
// Tests 'pop state' bit
|
||||
if (color & LogColor_PopStateBit)
|
||||
{
|
||||
if (!m_colors.empty())
|
||||
{
|
||||
m_color = m_colors.top();
|
||||
m_colors.pop();
|
||||
}
|
||||
else { m_color = LogColor_Default; }
|
||||
}
|
||||
|
||||
// Tests 'reset' bit
|
||||
if (color & LogColor_ResetBit) { m_color = LogColor_Default; }
|
||||
|
||||
// Tests 'foreground' bit
|
||||
if (color & LogColor_ForegroundBit)
|
||||
{
|
||||
// Tests 'color' bit
|
||||
if (color & LogColor_ForegroundColorBit)
|
||||
{
|
||||
const ELogColor colorMask = ELogColor(LogColor_ForegroundColorRedBit | LogColor_ForegroundColorGreenBit | LogColor_ForegroundColorBlueBit);
|
||||
m_color = ELogColor(m_color & (~colorMask));
|
||||
m_color = ELogColor(m_color | (color & colorMask) | LogColor_ForegroundBit | LogColor_ForegroundColorBit);
|
||||
}
|
||||
|
||||
// Test 'light' bit
|
||||
if (color & LogColor_ForegroundLightBit)
|
||||
{
|
||||
const ELogColor lightMask = ELogColor(LogColor_ForegroundLightBit | LogColor_ForegroundLightStateBit);
|
||||
m_color = ELogColor(m_color & (~lightMask));
|
||||
m_color = ELogColor(m_color | (color & lightMask) | LogColor_ForegroundBit);
|
||||
}
|
||||
|
||||
// Test 'blink' bit
|
||||
if (color & LogColor_ForegroundBlinkBit)
|
||||
{
|
||||
const ELogColor blinkMask = ELogColor(LogColor_ForegroundBlinkBit | LogColor_ForegroundBlinkStateBit);
|
||||
m_color = ELogColor(m_color & (~blinkMask));
|
||||
m_color = ELogColor(m_color | (color & blinkMask) | LogColor_ForegroundBit);
|
||||
}
|
||||
|
||||
// Test 'bold' bit
|
||||
if (color & LogColor_ForegroundBoldBit)
|
||||
{
|
||||
const ELogColor boldMask = ELogColor(LogColor_ForegroundBoldBit | LogColor_ForegroundBoldStateBit);
|
||||
m_color = ELogColor(m_color & (~boldMask));
|
||||
m_color = ELogColor(m_color | (color & boldMask) | LogColor_ForegroundBit);
|
||||
}
|
||||
|
||||
// Test 'underline' bit
|
||||
if (color & LogColor_ForegroundUnderlineBit)
|
||||
{
|
||||
const ELogColor underlineMask = ELogColor(LogColor_ForegroundBlinkBit | LogColor_ForegroundBlinkStateBit);
|
||||
m_color = ELogColor(m_color & (~underlineMask));
|
||||
m_color = ELogColor(m_color | (color & underlineMask) | LogColor_ForegroundBit);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests 'background' bit
|
||||
if (color & LogColor_BackgroundBit)
|
||||
{
|
||||
// Tests 'color' bit
|
||||
if (color & LogColor_BackgroundColorBit)
|
||||
{
|
||||
const ELogColor colorMask = ELogColor(LogColor_BackgroundColorRedBit | LogColor_BackgroundColorGreenBit | LogColor_BackgroundColorBlueBit);
|
||||
m_color = ELogColor(m_color & (~colorMask));
|
||||
m_color = ELogColor(m_color | (color & colorMask) | LogColor_BackgroundBit | LogColor_BackgroundColorBit);
|
||||
}
|
||||
|
||||
// Test 'light' bit
|
||||
if (color & LogColor_BackgroundLightBit)
|
||||
{
|
||||
const ELogColor lightMask = ELogColor(LogColor_BackgroundLightBit | LogColor_BackgroundLightStateBit);
|
||||
m_color = ELogColor(m_color & (~lightMask));
|
||||
m_color = ELogColor(m_color | (color & lightMask) | LogColor_BackgroundBit);
|
||||
}
|
||||
|
||||
// Test 'blink' bit
|
||||
if (color & LogColor_BackgroundBlinkBit)
|
||||
{
|
||||
const ELogColor blinkMask = ELogColor(LogColor_BackgroundBlinkBit | LogColor_BackgroundBlinkStateBit);
|
||||
m_color = ELogColor(m_color & (~blinkMask));
|
||||
m_color = ELogColor(m_color | (color & blinkMask) | LogColor_BackgroundBit);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally applies current color
|
||||
applyColor();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
|
||||
void CLogListenerConsole::applyColor()
|
||||
{
|
||||
int gotACommand=0;
|
||||
|
||||
#define _command_separator_ (gotACommand++?";":"")
|
||||
|
||||
std::cout << "\033[00m";
|
||||
|
||||
if(m_color!=LogColor_Default)
|
||||
{
|
||||
std::cout << "\033[";
|
||||
|
||||
if(m_color&LogColor_ForegroundBit)
|
||||
{
|
||||
if(m_color&LogColor_ForegroundLightBit && m_color&LogColor_ForegroundLightStateBit) { } // No function to do that
|
||||
|
||||
if(m_color&LogColor_ForegroundBoldBit && m_color&LogColor_ForegroundBoldStateBit)
|
||||
{
|
||||
std::cout << _command_separator_ << "01";
|
||||
}
|
||||
|
||||
if(m_color&LogColor_ForegroundUnderlineBit && m_color&LogColor_ForegroundUnderlineStateBit)
|
||||
{
|
||||
std::cout << _command_separator_ << "04";
|
||||
}
|
||||
|
||||
if(m_color&LogColor_ForegroundBlinkBit && m_color&LogColor_ForegroundBlinkStateBit)
|
||||
{
|
||||
std::cout << _command_separator_ << "05";
|
||||
}
|
||||
|
||||
if(m_color&LogColor_ForegroundColorBit)
|
||||
{
|
||||
ELogColor color=ELogColor(m_color&(LogColor_ForegroundBit|LogColor_ForegroundColorBit|LogColor_ForegroundColorRedBit|LogColor_ForegroundColorGreenBit|LogColor_ForegroundColorBlueBit));
|
||||
switch(color)
|
||||
{
|
||||
case LogColor_ForegroundBlack: std::cout << _command_separator_ << "30"; break;
|
||||
case LogColor_ForegroundRed: std::cout << _command_separator_ << "31"; break;
|
||||
case LogColor_ForegroundGreen: std::cout << _command_separator_ << "32"; break;
|
||||
case LogColor_ForegroundYellow: std::cout << _command_separator_ << "33"; break;
|
||||
case LogColor_ForegroundBlue: std::cout << _command_separator_ << "34"; break;
|
||||
case LogColor_ForegroundMagenta: std::cout << _command_separator_ << "35"; break;
|
||||
case LogColor_ForegroundCyan: std::cout << _command_separator_ << "36"; break;
|
||||
case LogColor_ForegroundWhite: std::cout << _command_separator_ << "37"; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_color&LogColor_BackgroundBit)
|
||||
{
|
||||
if(m_color&LogColor_BackgroundColorBit)
|
||||
{
|
||||
ELogColor color=ELogColor(m_color&(LogColor_BackgroundBit|LogColor_BackgroundColorBit|LogColor_BackgroundColorRedBit|LogColor_BackgroundColorGreenBit|LogColor_BackgroundColorBlueBit));
|
||||
switch(color)
|
||||
{
|
||||
case LogColor_BackgroundBlack: std::cout << _command_separator_ << "40"; break;
|
||||
case LogColor_BackgroundRed: std::cout << _command_separator_ << "41"; break;
|
||||
case LogColor_BackgroundGreen: std::cout << _command_separator_ << "42"; break;
|
||||
case LogColor_BackgroundYellow: std::cout << _command_separator_ << "43"; break;
|
||||
case LogColor_BackgroundBlue: std::cout << _command_separator_ << "44"; break;
|
||||
case LogColor_BackgroundMagenta: std::cout << _command_separator_ << "45"; break;
|
||||
case LogColor_BackgroundCyan: std::cout << _command_separator_ << "46"; break;
|
||||
case LogColor_BackgroundWhite: std::cout << _command_separator_ << "47"; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_color&LogColor_BackgroundLightBit && m_color&LogColor_BackgroundLightStateBit) { } // No function to do that
|
||||
if(m_color&LogColor_BackgroundBlinkBit && m_color&LogColor_BackgroundBlinkStateBit) { } // No function to do that
|
||||
}
|
||||
|
||||
std::cout << "m";
|
||||
}
|
||||
|
||||
#undef _command_separator_
|
||||
|
||||
}
|
||||
|
||||
#elif defined TARGET_OS_Windows
|
||||
|
||||
void CLogListenerConsole::applyColor()
|
||||
{
|
||||
WORD attribute = 0;
|
||||
|
||||
if (m_color & LogColor_ForegroundBit)
|
||||
{
|
||||
if (m_color & LogColor_ForegroundColorBit)
|
||||
{
|
||||
attribute |= ((m_color & LogColor_ForegroundColorRedBit) ? FOREGROUND_RED : 0);
|
||||
attribute |= ((m_color & LogColor_ForegroundColorGreenBit) ? FOREGROUND_GREEN : 0);
|
||||
attribute |= ((m_color & LogColor_ForegroundColorBlueBit) ? FOREGROUND_BLUE : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute |= FOREGROUND_RED;
|
||||
attribute |= FOREGROUND_GREEN;
|
||||
attribute |= FOREGROUND_BLUE;
|
||||
}
|
||||
|
||||
if (m_color & LogColor_ForegroundLightBit && m_color & LogColor_ForegroundLightStateBit) { attribute |= FOREGROUND_INTENSITY; }
|
||||
if (m_color & LogColor_ForegroundBoldBit && m_color & LogColor_ForegroundBoldStateBit) { } // No function to do that
|
||||
if (m_color & LogColor_ForegroundUnderlineBit && m_color & LogColor_ForegroundUnderlineStateBit) { attribute |= COMMON_LVB_UNDERSCORE; }
|
||||
if (m_color & LogColor_ForegroundBlinkBit && m_color & LogColor_ForegroundBlinkStateBit) { } // No function to do that
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute |= FOREGROUND_RED;
|
||||
attribute |= FOREGROUND_GREEN;
|
||||
attribute |= FOREGROUND_BLUE;
|
||||
}
|
||||
|
||||
if (m_color & LogColor_BackgroundBit)
|
||||
{
|
||||
if (m_color & LogColor_BackgroundColorBit)
|
||||
{
|
||||
attribute |= ((m_color & LogColor_BackgroundColorRedBit) ? BACKGROUND_RED : 0);
|
||||
attribute |= ((m_color & LogColor_BackgroundColorGreenBit) ? BACKGROUND_GREEN : 0);
|
||||
attribute |= ((m_color & LogColor_BackgroundColorBlueBit) ? BACKGROUND_BLUE : 0);
|
||||
}
|
||||
|
||||
if (m_color & LogColor_BackgroundLightBit && m_color & LogColor_BackgroundLightStateBit) { attribute |= BACKGROUND_INTENSITY; }
|
||||
|
||||
if (m_color & LogColor_BackgroundBlinkBit && m_color & LogColor_BackgroundBlinkStateBit)
|
||||
{
|
||||
// No function to do that
|
||||
}
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attribute);
|
||||
}
|
||||
|
||||
#else
|
||||
void CLogListenerConsole::applyColor() { }
|
||||
#endif
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <stack>
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
class CLogListenerConsole final : public TKernelObject<ILogListener>
|
||||
{
|
||||
public:
|
||||
|
||||
CLogListenerConsole(const IKernelContext& ctx, const CString& sApplicationName);
|
||||
bool isActive(const ELogLevel level) override;
|
||||
bool activate(const ELogLevel level, const bool active) override;
|
||||
bool activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active) override;
|
||||
bool activate(const bool active) override;
|
||||
|
||||
void configure(const IConfigurationManager& configManager);
|
||||
void log(const CTime value) override;
|
||||
void log(const uint64_t value) override;
|
||||
void log(const uint32_t value) override;
|
||||
void log(const int64_t value) override;
|
||||
void log(const int value) override;
|
||||
void log(const double value) override;
|
||||
void log(const bool value) override;
|
||||
void log(const CIdentifier& value) override;
|
||||
void log(const CString& value) override;
|
||||
void log(const std::string& value) override;
|
||||
void log(const char* value) override;
|
||||
void log(const ELogLevel level) override;
|
||||
void log(const ELogColor color) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<ILogListener>, OVK_ClassId_Kernel_Log_LogListenerConsole)
|
||||
|
||||
protected:
|
||||
|
||||
void applyColor();
|
||||
|
||||
std::map<ELogLevel, bool> m_activeLevels;
|
||||
std::stack<ELogColor> m_colors;
|
||||
ELogColor m_color;
|
||||
CString m_applicationName;
|
||||
|
||||
bool m_logWithHexa = false;
|
||||
bool m_timeInSeconds = false;
|
||||
uint64_t m_timePrecision = 0;
|
||||
bool m_useColor = false;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "ovkCLogListenerFile.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <fs/Files.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CLogListenerFile::CLogListenerFile(const IKernelContext& ctx, const CString& applicationName, const CString& logFilename)
|
||||
: TKernelObject<ILogListener>(ctx), m_applicationName(applicationName), m_logFilename(logFilename)
|
||||
{
|
||||
// Create the path to the log file
|
||||
FS::Files::createParentPath(logFilename.toASCIIString());
|
||||
|
||||
FS::Files::openFStream(m_fsFileStream, logFilename.toASCIIString(), std::ios_base::out);
|
||||
|
||||
if (!m_fsFileStream.is_open())
|
||||
{
|
||||
std::cout << "[ ERR ] Error while creating FileLogListener into '" << logFilename << "'" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_fsFileStream << std::flush;
|
||||
}
|
||||
|
||||
void CLogListenerFile::configure(const IConfigurationManager& configurationManager)
|
||||
{
|
||||
m_timeInSeconds = configurationManager.expandAsBoolean("${Kernel_FileLogTimeInSecond}", false);
|
||||
m_logWithHexa = configurationManager.expandAsBoolean("${Kernel_FileLogWithHexa}", true);
|
||||
m_timePrecision = configurationManager.expandAsUInteger("${Kernel_FileLogTimePrecision}", 3);
|
||||
}
|
||||
|
||||
bool CLogListenerFile::isActive(const ELogLevel level)
|
||||
{
|
||||
const auto it = m_activeLevels.find(level);
|
||||
if (it == m_activeLevels.end()) { return true; }
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool CLogListenerFile::activate(const ELogLevel level, const bool active)
|
||||
{
|
||||
m_activeLevels[level] = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogListenerFile::activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active)
|
||||
{
|
||||
for (int i = startLevel; i <= endLevel; ++i) { m_activeLevels[ELogLevel(i)] = active; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogListenerFile::activate(const bool active) { return activate(LogLevel_First, LogLevel_Last, active); }
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
class CLogListenerFile final : public TKernelObject<ILogListener>
|
||||
{
|
||||
public:
|
||||
|
||||
CLogListenerFile(const IKernelContext& ctx, const CString& applicationName, const CString& logFilename);
|
||||
~CLogListenerFile() override { m_fsFileStream.close(); }
|
||||
bool isActive(const ELogLevel level) override;
|
||||
bool activate(const ELogLevel level, const bool active) override;
|
||||
bool activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active) override;
|
||||
bool activate(const bool active) override;
|
||||
|
||||
void configure(const IConfigurationManager& configurationManager);
|
||||
void log(const CTime value) override { m_fsFileStream << value.str(m_timeInSeconds, m_logWithHexa); }
|
||||
void log(const uint64_t value) override { logInteger(value); }
|
||||
void log(const uint32_t value) override { logInteger(value); }
|
||||
void log(const int64_t value) override { logInteger(value); }
|
||||
void log(const int value) override { logInteger(value); }
|
||||
void log(const double value) override { m_fsFileStream << value; }
|
||||
void log(const bool value) override { m_fsFileStream << (value ? "true" : "false"); }
|
||||
void log(const CIdentifier& value) override { m_fsFileStream << value.str(); }
|
||||
void log(const CString& value) override { m_fsFileStream << value << std::flush; }
|
||||
void log(const std::string& value) override { m_fsFileStream << value << std::flush; }
|
||||
void log(const char* value) override { m_fsFileStream << value << std::flush; }
|
||||
void log(const ELogLevel level) override { m_fsFileStream << toString(level); }
|
||||
void log(const ELogColor /*color*/) override { }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<ILogListener>, OVK_ClassId_Kernel_Log_LogListenerFile)
|
||||
|
||||
protected:
|
||||
|
||||
std::map<ELogLevel, bool> m_activeLevels;
|
||||
CString m_applicationName;
|
||||
CString m_logFilename;
|
||||
std::fstream m_fsFileStream;
|
||||
|
||||
// Log Settings
|
||||
bool m_timeInSeconds = true;
|
||||
bool m_logWithHexa = false;
|
||||
uint64_t m_timePrecision = 3;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void logInteger(T value)
|
||||
{
|
||||
m_fsFileStream << value << " ";
|
||||
if (m_logWithHexa)
|
||||
{
|
||||
m_fsFileStream.setf(std::ios::hex);
|
||||
m_fsFileStream << "(" << value << ")";
|
||||
m_fsFileStream.unsetf(std::ios::hex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "ovkCLogManager.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
bool CLogManager::isActive(const ELogLevel level)
|
||||
{
|
||||
const auto it = m_activeLevels.find(level);
|
||||
if (it == m_activeLevels.end()) { return true; }
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool CLogManager::activate(const ELogLevel level, const bool active)
|
||||
{
|
||||
m_activeLevels[level] = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogManager::activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active)
|
||||
{
|
||||
for (int i = startLevel; i <= endLevel; ++i) { m_activeLevels[ELogLevel(i)] = active; }
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLogManager::log(const char* value)
|
||||
{
|
||||
logForEach<const char*>(value);
|
||||
{
|
||||
GRAB_OWNERSHIP;
|
||||
|
||||
std::string copy(value);
|
||||
if (copy.length() > 0 && copy[copy.length() - 1] == '\n')
|
||||
{
|
||||
// we are done, release
|
||||
m_owner = std::thread::id();
|
||||
m_condition.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLogManager::log(const ELogLevel level)
|
||||
{
|
||||
{
|
||||
GRAB_OWNERSHIP;
|
||||
m_currentLogLevel = level;
|
||||
}
|
||||
|
||||
logForEach<ELogLevel>(level);
|
||||
}
|
||||
|
||||
bool CLogManager::addListener(ILogListener* listener)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
if (listener == nullptr) { return false; }
|
||||
|
||||
auto it = m_listeners.begin();
|
||||
while (it != m_listeners.end())
|
||||
{
|
||||
if ((*it) == listener) { return false; }
|
||||
++it;
|
||||
}
|
||||
|
||||
m_listeners.push_back(listener);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogManager::removeListener(ILogListener* listener)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto it = m_listeners.begin();
|
||||
while (it != m_listeners.end())
|
||||
{
|
||||
if ((*it) == listener)
|
||||
{
|
||||
m_listeners.erase(it);
|
||||
return true; // due to constraint in addListener(), listener can be in the array only once, so we can return
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
class CLogManager final : public TKernelObject<ILogManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CLogManager(const IKernelContext& ctx) : TKernelObject<ILogManager>(ctx) {}
|
||||
bool isActive(const ELogLevel level) override;
|
||||
bool activate(const ELogLevel level, const bool active) override;
|
||||
bool activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active) override;
|
||||
bool activate(const bool active) override { return activate(LogLevel_First, LogLevel_Last, active); }
|
||||
void log(const CTime value) override { logForEach<const CTime>(value); }
|
||||
void log(const uint64_t value) override { logForEach<const uint64_t>(value); }
|
||||
void log(const uint32_t value) override { logForEach<const uint32_t>(value); }
|
||||
void log(const int64_t value) override { logForEach<const int64_t>(value); }
|
||||
void log(const int value) override { logForEach<const int>(value); }
|
||||
void log(const double value) override { logForEach<const double>(value); }
|
||||
void log(const bool value) override { logForEach<const bool>(value); }
|
||||
void log(const CIdentifier& value) override { logForEach<const CIdentifier&>(value); }
|
||||
void log(const CString& value) override { log(value.toASCIIString()); }
|
||||
void log(const std::string& value) override { log(value.c_str()); }
|
||||
void log(const char* value) override;
|
||||
void log(const ELogLevel level) override;
|
||||
void log(const ELogColor color) override { logForEach<ELogColor>(color); }
|
||||
bool addListener(ILogListener* listener) override;
|
||||
bool removeListener(ILogListener* listener) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<ILogManager>, OVK_ClassId_Kernel_Log_LogManager)
|
||||
|
||||
protected:
|
||||
|
||||
// This macro waits until m_oHolder is either the current thread id or unassigned
|
||||
#define GRAB_OWNERSHIP std::unique_lock<std::mutex> lock(m_mutex); \
|
||||
m_condition.wait(lock, [this]() { return (this->m_owner == std::thread::id() || this->m_owner == std::this_thread::get_id() ); } ); \
|
||||
m_owner = std::this_thread::get_id();
|
||||
|
||||
template <class T>
|
||||
void logForEach(T tValue)
|
||||
{
|
||||
GRAB_OWNERSHIP;
|
||||
|
||||
if (m_currentLogLevel != LogLevel_None && this->isActive(m_currentLogLevel))
|
||||
{
|
||||
for (auto i = m_listeners.begin(); i != m_listeners.end(); ++i) { if ((*i)->isActive(m_currentLogLevel)) { (*i)->log(tValue); } }
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ILogListener*> m_listeners;
|
||||
std::map<ELogLevel, bool> m_activeLevels;
|
||||
ELogLevel m_currentLogLevel = LogLevel_Info;
|
||||
|
||||
// Variables to make sure only one thread writes to the LogManager at a time.
|
||||
// Concurrency control operating logic:
|
||||
// Calling log() will wait until it obtains logmanager ownership for the calling thread
|
||||
// Only thread having the ownership can write to the log
|
||||
// After a thread logs an entry ending in an EOL character, the ownership is freed.
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
std::thread::id m_owner;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
#include "ovkCMetaboxManager.h"
|
||||
|
||||
#include <fs/IEntryEnumerator.h>
|
||||
|
||||
#include <map>
|
||||
#include <random>
|
||||
|
||||
#include "ovp_global_defines.h"
|
||||
#include "ovkCMetaboxObjectDesc.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CMetaboxManagerEntryEnumeratorCallBack final : public TKernelObject<IObject>, public FS::IEntryEnumeratorCallBack
|
||||
{
|
||||
public:
|
||||
|
||||
CMetaboxManagerEntryEnumeratorCallBack(const IKernelContext& ctx, CMetaboxManager& metaboxManager)
|
||||
: TKernelObject<IObject>(ctx), m_manager(metaboxManager) { m_n = 0; }
|
||||
|
||||
bool callback(FS::IEntryEnumerator::IEntry& rEntry, FS::IEntryEnumerator::IAttributes& rAttributes) override
|
||||
{
|
||||
if (rAttributes.isFile())
|
||||
{
|
||||
const char* fullFileName = rEntry.getName();
|
||||
|
||||
CIdentifier scenarioID, metaboxId, metaboxHash;
|
||||
this->getKernelContext().getScenarioManager().
|
||||
importScenarioFromFile(scenarioID, OV_ScenarioImportContext_OnLoadMetaboxImport, fullFileName);
|
||||
if (scenarioID != CIdentifier::undefined())
|
||||
{
|
||||
IScenario& metaboxScenario = this->getKernelContext().getScenarioManager().getScenario(scenarioID);
|
||||
const bool isValid = metaboxId.fromString(metaboxScenario.getAttributeValue(OVP_AttributeId_Metabox_ID));
|
||||
if (isValid && metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_Name) != CString())
|
||||
{
|
||||
const bool hasHash = metaboxHash.fromString(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_MetaboxHash));
|
||||
if (!hasHash)
|
||||
{
|
||||
this->getKernelContext().getLogManager() << LogLevel_Warning << "The metabox " << metaboxId.str() <<
|
||||
" has no Hash in the scenario " << fullFileName << "\n";
|
||||
}
|
||||
m_manager.setMetaboxFilePath(metaboxId, CString(fullFileName));
|
||||
m_manager.setMetaboxHash(metaboxId, metaboxHash);
|
||||
m_manager.setMetaboxObjectDesc(metaboxId, new Metabox::CMetaboxObjectDesc(metaboxId.str().c_str(), metaboxScenario));
|
||||
m_n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->getKernelContext().getLogManager() << LogLevel_Warning << "The metabox file " << fullFileName <<
|
||||
" is missing elements. Please check it.\n";
|
||||
}
|
||||
}
|
||||
this->getKernelContext().getScenarioManager().releaseScenario(scenarioID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t resetMetaboxCount()
|
||||
{
|
||||
const size_t res = m_n;
|
||||
m_n = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IObject>, CIdentifier::undefined())
|
||||
protected:
|
||||
CMetaboxManager& m_manager;
|
||||
size_t m_n;
|
||||
};
|
||||
|
||||
|
||||
CMetaboxManager::CMetaboxManager(const IKernelContext& ctx) : TKernelObject<IMetaboxManager>(ctx)
|
||||
{
|
||||
this->TKernelObject<IMetaboxManager>::getScenarioManager().registerScenarioImporter(
|
||||
OV_ScenarioImportContext_OnLoadMetaboxImport, ".mxb", OVP_GD_ClassId_Algorithm_XMLScenarioImporter);
|
||||
this->TKernelObject<IMetaboxManager>::getScenarioManager().registerScenarioImporter(
|
||||
OV_ScenarioImportContext_OnLoadMetaboxImport, ".xml", OVP_GD_ClassId_Algorithm_XMLScenarioImporter);
|
||||
}
|
||||
|
||||
bool CMetaboxManager::addMetaboxesFromFiles(const CString& fileNameWildCard)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Info << "Adding metaboxes from [" << fileNameWildCard << "]\n";
|
||||
|
||||
CMetaboxManagerEntryEnumeratorCallBack callBack(this->getKernelContext(), *this); //, m_pluginModules, m_pluginObjectDescs, haveAllPluginsLoadedCorrectly);
|
||||
FS::IEntryEnumerator* entryEnumerator = createEntryEnumerator(callBack);
|
||||
std::stringstream ss(fileNameWildCard.toASCIIString());
|
||||
std::string path;
|
||||
while (getline(ss, path, ';'))
|
||||
{
|
||||
bool result = false; // Used to output imported metabox count
|
||||
CString ext("");
|
||||
while ((ext = this->getScenarioManager().getNextScenarioImporter(OV_ScenarioImportContext_OnLoadMetaboxImport, ext)) != CString(""))
|
||||
{
|
||||
result |= entryEnumerator->enumerate((path + "*" + ext.toASCIIString()).c_str());
|
||||
}
|
||||
if (result) { this->getLogManager() << LogLevel_Info << "Added " << callBack.resetMetaboxCount() << " metaboxes from [" << path << "]\n"; }
|
||||
}
|
||||
entryEnumerator->release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CMetaboxManager::getNextMetaboxObjectDescIdentifier(const CIdentifier& previousID) const
|
||||
{
|
||||
if (m_objectDesc.empty()) { return CIdentifier::undefined(); }
|
||||
if (previousID == CIdentifier::undefined()) { return m_objectDesc.begin()->first; }
|
||||
|
||||
const auto result = m_objectDesc.find(previousID);
|
||||
if (result == m_objectDesc.end() || std::next(result, 1) == m_objectDesc.end()) { return CIdentifier::undefined(); }
|
||||
return std::next(result, 1)->first;
|
||||
}
|
||||
|
||||
const Plugins::IPluginObjectDesc* CMetaboxManager::getMetaboxObjectDesc(const CIdentifier& metaboxID) const
|
||||
{
|
||||
const auto result = m_objectDesc.find(metaboxID);
|
||||
return result != m_objectDesc.end() ? result->second : nullptr;
|
||||
}
|
||||
|
||||
CString CMetaboxManager::getMetaboxFilePath(const CIdentifier& metaboxID) const
|
||||
{
|
||||
const auto resultIt = m_filepath.find(metaboxID);
|
||||
return resultIt != m_filepath.end() ? resultIt->second : CString();
|
||||
}
|
||||
|
||||
CIdentifier CMetaboxManager::getMetaboxHash(const CIdentifier& metaboxID) const
|
||||
{
|
||||
const auto resultIt = m_hash.find(metaboxID);
|
||||
return resultIt != m_hash.end() ? resultIt->second : CIdentifier::undefined();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CMetaboxManager final : public TKernelObject<IMetaboxManager>
|
||||
{
|
||||
public:
|
||||
explicit CMetaboxManager(const IKernelContext& ctx);
|
||||
~CMetaboxManager() override { for (auto& desc : m_objectDesc) { delete desc.second; } }
|
||||
bool addMetaboxesFromFiles(const CString& fileNameWildCard) override;
|
||||
CIdentifier getNextMetaboxObjectDescIdentifier(const CIdentifier& previousID) const override;
|
||||
const Plugins::IPluginObjectDesc* getMetaboxObjectDesc(const CIdentifier& metaboxID) const override;
|
||||
void setMetaboxObjectDesc(const CIdentifier& metaboxID, Plugins::IPluginObjectDesc* metaboxDesc) override { m_objectDesc[metaboxID] = metaboxDesc; }
|
||||
CString getMetaboxFilePath(const CIdentifier& metaboxID) const override;
|
||||
void setMetaboxFilePath(const CIdentifier& metaboxID, const CString& filePath) override { m_filepath[metaboxID] = filePath; }
|
||||
CIdentifier getMetaboxHash(const CIdentifier& metaboxID) const override;
|
||||
void setMetaboxHash(const CIdentifier& metaboxID, const CIdentifier& hash) override { m_hash[metaboxID] = hash; }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IMetaboxManager>, OVK_ClassId_Kernel_Metaboxes_MetaboxManager)
|
||||
|
||||
protected:
|
||||
std::map<CIdentifier, const Plugins::IPluginObjectDesc*> m_objectDesc;
|
||||
std::map<CIdentifier, CString> m_filepath;
|
||||
std::map<CIdentifier, CIdentifier> m_hash;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
#include "ovkCMetaboxObjectDesc.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Metabox {
|
||||
|
||||
CMetaboxObjectDesc::CMetaboxObjectDesc(const CString& rMetaboxDescriptor, Kernel::IScenario& metaboxScenario)
|
||||
: m_metaboxDesc(rMetaboxDescriptor)
|
||||
, m_name(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_Name))
|
||||
, m_authorName(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_Author))
|
||||
, m_authorCompanyName(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_Company))
|
||||
, m_shortDesc(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_ShortDescription))
|
||||
, m_detailedDesc(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_DetailedDescription))
|
||||
, m_category(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_Category))
|
||||
, m_version(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_Version))
|
||||
, m_stockItemName("")
|
||||
, m_addedSoftwareVersion(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_AddedSoftwareVersion))
|
||||
, m_updatedSoftwareVersion(metaboxScenario.getAttributeValue(OV_AttributeId_Scenario_UpdatedSoftwareVersion))
|
||||
, m_metaboxID(metaboxScenario.getAttributeValue(OVP_AttributeId_Metabox_ID))
|
||||
{
|
||||
for (size_t scenarioInputIdx = 0; scenarioInputIdx < metaboxScenario.getInputCount(); ++scenarioInputIdx)
|
||||
{
|
||||
CString name;
|
||||
CIdentifier typeID;
|
||||
CIdentifier id;
|
||||
|
||||
metaboxScenario.getInputType(scenarioInputIdx, typeID);
|
||||
metaboxScenario.getInputName(scenarioInputIdx, name);
|
||||
metaboxScenario.getInterfacorIdentifier(Kernel::EBoxInterfacorType::Input, scenarioInputIdx, id);
|
||||
|
||||
m_inputs.push_back(io_stream_t(name, typeID, id));
|
||||
}
|
||||
|
||||
for (size_t scenarioOutputIdx = 0; scenarioOutputIdx < metaboxScenario.getOutputCount(); ++scenarioOutputIdx)
|
||||
{
|
||||
CString name;
|
||||
CIdentifier typeID;
|
||||
CIdentifier id;
|
||||
|
||||
metaboxScenario.getOutputType(scenarioOutputIdx, typeID);
|
||||
metaboxScenario.getOutputName(scenarioOutputIdx, name);
|
||||
metaboxScenario.getInterfacorIdentifier(Kernel::EBoxInterfacorType::Output, scenarioOutputIdx, id);
|
||||
|
||||
m_outputs.push_back(io_stream_t(name, typeID, id));
|
||||
}
|
||||
|
||||
for (size_t scenarioSettingIdx = 0; scenarioSettingIdx < metaboxScenario.getSettingCount(); ++scenarioSettingIdx)
|
||||
{
|
||||
CString name;
|
||||
CIdentifier typeID;
|
||||
CString defaultValue;
|
||||
CIdentifier id;
|
||||
|
||||
metaboxScenario.getSettingName(scenarioSettingIdx, name);
|
||||
metaboxScenario.getSettingType(scenarioSettingIdx, typeID);
|
||||
metaboxScenario.getSettingDefaultValue(scenarioSettingIdx, defaultValue);
|
||||
metaboxScenario.getInterfacorIdentifier(Kernel::EBoxInterfacorType::Setting, scenarioSettingIdx, id);
|
||||
|
||||
m_settings.push_back(setting_t(name, typeID, defaultValue, id));
|
||||
}
|
||||
}
|
||||
|
||||
bool CMetaboxObjectDesc::getBoxPrototype(Kernel::IBoxProto& prototype) const
|
||||
{
|
||||
for (const auto& input : m_inputs) { prototype.addInput(input.m_name, input.m_typeID, input.m_id); }
|
||||
for (const auto& output : m_outputs) { prototype.addOutput(output.m_name, output.m_typeID, output.m_id); }
|
||||
for (const auto& setting : m_settings) { prototype.addSetting(setting.m_name, setting.m_typeID, setting.m_defaultValue, false, setting.m_id); }
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Metabox
|
||||
} // namespace OpenViBE
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Metabox {
|
||||
|
||||
/**
|
||||
* \brief The CMetaboxObjectDesc virtual BoxAlgorithmDesc for metaboxes
|
||||
*
|
||||
* This class provides a virtual algorithm descriptor for metaboxes. Each metabox-scenario
|
||||
* will result in one of these descriptors. The prototype is created from scenario inputs,
|
||||
* outputs and settings.
|
||||
*
|
||||
* Variables such as name, author etc are pulled from scenario information.
|
||||
*/
|
||||
class CMetaboxObjectDesc final : virtual public IMetaboxObjectDesc
|
||||
{
|
||||
public:
|
||||
CMetaboxObjectDesc() { }
|
||||
|
||||
CMetaboxObjectDesc(const CString& rMetaboxDescriptor, Kernel::IScenario& metaboxScenario);
|
||||
void release() override { }
|
||||
CString getMetaboxDescriptor() const override { return m_metaboxDesc; }
|
||||
CString getName() const override { return m_name; }
|
||||
CString getAuthorName() const override { return m_authorName; }
|
||||
CString getAuthorCompanyName() const override { return m_authorCompanyName; }
|
||||
CString getShortDescription() const override { return m_shortDesc; }
|
||||
CString getDetailedDescription() const override { return m_detailedDesc; }
|
||||
CString getCategory() const override { return m_category; }
|
||||
CString getVersion() const override { return m_version; }
|
||||
CString getStockItemName() const override { return m_stockItemName; }
|
||||
CString getAddedSoftwareVersion() const override { return m_addedSoftwareVersion; }
|
||||
CString getUpdatedSoftwareVersion() const override { return m_updatedSoftwareVersion; }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_Metabox; }
|
||||
Plugins::IPluginObject* create() override { return nullptr; }
|
||||
|
||||
// Handling of the virtual prototype
|
||||
|
||||
// Since we have to construct a prototype on the fly, the special Metabox descriptor
|
||||
// will also hold the information about the settings, inputs and outputs of the box
|
||||
typedef struct SStream
|
||||
{
|
||||
SStream() : m_name(""), m_typeID(CIdentifier::undefined()), m_id(CIdentifier::undefined()) {}
|
||||
|
||||
SStream(const CString& name, const CIdentifier& typeID, const CIdentifier& identifier)
|
||||
: m_name(name), m_typeID(typeID), m_id(identifier) {}
|
||||
|
||||
CString m_name;
|
||||
CIdentifier m_typeID = CIdentifier::undefined();
|
||||
CIdentifier m_id = CIdentifier::undefined();
|
||||
} io_stream_t;
|
||||
|
||||
typedef struct SSetting
|
||||
{
|
||||
SSetting()
|
||||
: m_name(""), m_typeID(CIdentifier::undefined()), m_defaultValue(""), m_id(CIdentifier::undefined()) {}
|
||||
|
||||
SSetting(const CString& name, const CIdentifier& typeID, const CString& value, const CIdentifier& id)
|
||||
: m_name(name), m_typeID(typeID), m_defaultValue(value), m_id(id) { }
|
||||
|
||||
CString m_name;
|
||||
CIdentifier m_typeID = CIdentifier::undefined();
|
||||
CString m_defaultValue;
|
||||
CIdentifier m_id = CIdentifier::undefined();
|
||||
} setting_t;
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(IMetaboxObjectDesc, OVP_ClassId_BoxAlgorithm_MetaboxDesc)
|
||||
|
||||
private:
|
||||
CString m_metaboxDesc;
|
||||
|
||||
CString m_name;
|
||||
CString m_authorName;
|
||||
CString m_authorCompanyName;
|
||||
CString m_shortDesc;
|
||||
CString m_detailedDesc;
|
||||
CString m_category;
|
||||
CString m_version;
|
||||
CString m_stockItemName;
|
||||
CString m_addedSoftwareVersion;
|
||||
CString m_updatedSoftwareVersion;
|
||||
CString m_metaboxID;
|
||||
|
||||
std::vector<io_stream_t> m_inputs;
|
||||
std::vector<io_stream_t> m_outputs;
|
||||
std::vector<setting_t> m_settings;
|
||||
};
|
||||
} // namespace Metabox
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
#include "ovkTConfigurable.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
typedef TBaseConfigurable<TKernelObject<IConfigurable>> configurable;
|
||||
|
||||
class CConfigurable final : public configurable
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CConfigurable(const IKernelContext& ctx) : TBaseConfigurable<TKernelObject<IConfigurable>>(ctx) { }
|
||||
|
||||
_IsDerivedFromClass_Final_(configurable, OVK_ClassId_Kernel_Configurable)
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,316 @@
|
||||
#include "ovkCKernelContext.h"
|
||||
#include "ovkCKernelObjectFactory.h"
|
||||
#include "ovkCTypeManager.h"
|
||||
|
||||
#include <openvibe/CIdentifier.hpp>
|
||||
|
||||
#include "algorithm/ovkCAlgorithmManager.h"
|
||||
#include "configuration/ovkCConfigurationManager.h"
|
||||
#include "player/ovkCPlayerManager.h"
|
||||
#include "plugins/ovkCPluginManager.h"
|
||||
#include "metabox/ovkCMetaboxManager.h"
|
||||
#include "scenario/ovkCScenarioManager.h"
|
||||
#include "log/ovkCLogManager.h"
|
||||
#include "log/ovkCLogListenerConsole.h"
|
||||
#include "log/ovkCLogListenerFile.h"
|
||||
#include "error/ovkCErrorManager.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
|
||||
#include <fs/Files.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CKernelContext::CKernelContext(const IKernelContext* masterKernelCtx, const CString& applicationName, const CString& configFile)
|
||||
: m_masterKernelCtx(masterKernelCtx ? *masterKernelCtx : *this), m_algorithmManager(nullptr), m_configManager(nullptr),
|
||||
m_kernelObjectFactory(nullptr), m_playerManager(nullptr), m_pluginManager(nullptr), m_metaboxManager(nullptr), m_scenarioManager(nullptr),
|
||||
m_typeManager(nullptr), m_logManager(nullptr), m_errorManager(nullptr), m_applicationName(applicationName), m_configFile(configFile),
|
||||
m_logListenerConsole(nullptr), m_logListenerFile(nullptr) {}
|
||||
|
||||
CKernelContext::~CKernelContext() { this->uninitialize(); }
|
||||
|
||||
bool CKernelContext::initialize(const char* const* tokenList, size_t nToken)
|
||||
{
|
||||
std::map<std::string, std::string> initializationTokens;
|
||||
const auto tokens = tokenList;
|
||||
while (tokens && nToken > 0)
|
||||
{
|
||||
const auto key = tokenList++;
|
||||
const auto value = tokenList++;
|
||||
nToken--;
|
||||
initializationTokens[*key] = *value;
|
||||
}
|
||||
|
||||
m_errorManager.reset(new CErrorManager(m_masterKernelCtx));
|
||||
|
||||
m_kernelObjectFactory.reset(new CKernelObjectFactory(m_masterKernelCtx));
|
||||
|
||||
m_logManager.reset(new CLogManager(m_masterKernelCtx));
|
||||
m_logManager->activate(true);
|
||||
|
||||
m_configManager.reset(new CConfigurationManager(m_masterKernelCtx));
|
||||
// We create the configuration manager very soon to be able to deactivate the console log listener
|
||||
if (initializationTokens.count("Kernel_SilentConsole"))
|
||||
{
|
||||
m_configManager->createConfigurationToken("Kernel_SilentConsole", initializationTokens.at("Kernel_SilentConsole").c_str());
|
||||
}
|
||||
|
||||
if (!m_configManager->expandAsBoolean("${Kernel_SilentConsole}", false))
|
||||
{
|
||||
m_logListenerConsole.reset(new CLogListenerConsole(m_masterKernelCtx, m_applicationName));
|
||||
m_logListenerConsole->activate(false);
|
||||
m_logListenerConsole->activate(LogLevel_Info, LogLevel_Last, true);
|
||||
this->getLogManager().addListener(m_logListenerConsole.get());
|
||||
}
|
||||
|
||||
|
||||
m_configManager->createConfigurationToken("ApplicationName", m_applicationName);
|
||||
m_configManager->createConfigurationToken("Path_UserData", Directories::getUserDataDir());
|
||||
m_configManager->createConfigurationToken("Path_Log", Directories::getLogDir());
|
||||
m_configManager->createConfigurationToken("Path_Tmp", "${Path_UserData}/tmp");
|
||||
m_configManager->createConfigurationToken("Path_Lib", Directories::getLibDir());
|
||||
m_configManager->createConfigurationToken("Path_Bin", Directories::getBinDir());
|
||||
m_configManager->createConfigurationToken("Path_Data", Directories::getDataDir());
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
m_configManager->createConfigurationToken("OperatingSystem", "Windows");
|
||||
#elif defined TARGET_OS_Linux
|
||||
m_configManager->createConfigurationToken("OperatingSystem", "Linux");
|
||||
#elif defined TARGET_OS_MacOS
|
||||
m_configManager->createConfigurationToken("OperatingSystem", "MacOS");
|
||||
#else
|
||||
m_configManager->createConfigurationToken("OperatingSystem", "Unknown");
|
||||
#endif
|
||||
|
||||
m_configManager->createConfigurationToken("Kernel_PluginsPatternMacOS", "libopenvibe-plugins-*.dylib");
|
||||
m_configManager->createConfigurationToken("Kernel_PluginsPatternLinux", "libopenvibe-plugins-*.so");
|
||||
m_configManager->createConfigurationToken("Kernel_PluginsPatternWindows", "openvibe-plugins-*.dll");
|
||||
m_configManager->createConfigurationToken("Kernel_Plugins", "${Path_Lib}/${Kernel_PluginsPattern${OperatingSystem}}");
|
||||
|
||||
m_configManager->createConfigurationToken("Kernel_Metabox", "${Path_Data}/metaboxes/;${Path_UserData}/metaboxes/");
|
||||
|
||||
m_configManager->createConfigurationToken("Kernel_MainLogLevel", "Debug");
|
||||
m_configManager->createConfigurationToken("Kernel_ConsoleLogLevel", "Information");
|
||||
m_configManager->createConfigurationToken("Kernel_FileLogLevel", "Debug");
|
||||
m_configManager->createConfigurationToken("Kernel_PlayerFrequency", "128");
|
||||
// Add this two tokens to be used to know what documentation should be loaded
|
||||
m_configManager->createConfigurationToken("Brand_Name", BRAND_NAME);
|
||||
m_configManager->createConfigurationToken("Application_Name", OV_PROJECT_NAME);
|
||||
m_configManager->createConfigurationToken("Application_Version", OV_VERSION_MAJOR "." OV_VERSION_MINOR "." OV_VERSION_PATCH);
|
||||
|
||||
for (auto& token : initializationTokens) { m_configManager->addOrReplaceConfigurationToken(token.first.c_str(), token.second.c_str()); }
|
||||
|
||||
this->getLogManager() << LogLevel_Info << "Adding kernel configuration file [" << m_configFile << "]\n";
|
||||
|
||||
OV_ERROR_UNLESS_KRF(m_configManager->addConfigurationFromFile(m_configFile),
|
||||
"Problem parsing config file [" << m_configFile << "]", Kernel::ErrorType::Internal);
|
||||
|
||||
CString pathTmp = m_configManager->expand("${Path_UserData}");
|
||||
FS::Files::createPath(pathTmp.toASCIIString());
|
||||
pathTmp = m_configManager->expand("${Path_Tmp}");
|
||||
FS::Files::createPath(pathTmp.toASCIIString());
|
||||
pathTmp = m_configManager->expand("${Path_Log}");
|
||||
FS::Files::createPath(pathTmp);
|
||||
const CString logFile = pathTmp + "/openvibe-" + m_applicationName + ".log";
|
||||
|
||||
// We do this here to allow user to set the Path_Log in the .conf. The downside is that earlier log messages will not appear in the file log.
|
||||
m_logListenerFile.reset(new CLogListenerFile(m_masterKernelCtx, m_applicationName, logFile));
|
||||
m_logListenerFile->activate(true);
|
||||
this->getLogManager().addListener(m_logListenerFile.get());
|
||||
|
||||
const ELogLevel mainLogLevel = this->earlyGetLogLevel(m_configManager->expand("${Kernel_MainLogLevel}"));
|
||||
const ELogLevel consoleLogLevel = this->earlyGetLogLevel(m_configManager->expand("${Kernel_ConsoleLogLevel}"));
|
||||
const ELogLevel fileLogLevel = this->earlyGetLogLevel(m_configManager->expand("${Kernel_FileLogLevel}"));
|
||||
|
||||
m_logManager->activate(false);
|
||||
m_logManager->activate(mainLogLevel, LogLevel_Last, true);
|
||||
m_logListenerFile->activate(false);
|
||||
m_logListenerFile->activate(fileLogLevel, LogLevel_Last, true);
|
||||
m_logListenerFile->configure(*m_configManager);
|
||||
m_logListenerFile->configure(*m_configManager);
|
||||
|
||||
if (m_logListenerConsole)
|
||||
{
|
||||
m_logListenerConsole->activate(false);
|
||||
m_logListenerConsole->activate(consoleLogLevel, LogLevel_Last, true);
|
||||
m_logListenerConsole->configure(*m_configManager);
|
||||
}
|
||||
|
||||
m_algorithmManager.reset(new CAlgorithmManager(m_masterKernelCtx));
|
||||
m_playerManager.reset(new CPlayerManager(m_masterKernelCtx));
|
||||
m_typeManager.reset(new CTypeManager(m_masterKernelCtx));
|
||||
|
||||
m_typeManager->registerType(OV_TypeId_Boolean, "Boolean");
|
||||
m_typeManager->registerType(OV_TypeId_Integer, "Integer");
|
||||
m_typeManager->registerType(OV_TypeId_Float, "Float");
|
||||
m_typeManager->registerType(OV_TypeId_String, "String");
|
||||
m_typeManager->registerType(OV_TypeId_Filename, "Filename");
|
||||
m_typeManager->registerType(OV_TypeId_Script, "Script");
|
||||
|
||||
m_typeManager->registerEnumerationType(OV_TypeId_Stimulation, "Stimulation");
|
||||
|
||||
m_typeManager->registerEnumerationType(OV_TypeId_MeasurementUnit, "Measurement unit");
|
||||
m_typeManager->registerEnumerationType(OV_TypeId_Factor, "Factor");
|
||||
|
||||
m_typeManager->registerEnumerationType(OV_TypeId_LogLevel, "Log level");
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "None", LogLevel_None);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Debug", LogLevel_Debug);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Benchmarking / Profiling", LogLevel_Benchmark);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Trace", LogLevel_Trace);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Information", LogLevel_Info);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Warning", LogLevel_Warning);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Important warning", LogLevel_ImportantWarning);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Error", LogLevel_Error);
|
||||
m_typeManager->registerEnumerationEntry(OV_TypeId_LogLevel, "Fatal error", LogLevel_Fatal);
|
||||
|
||||
m_typeManager->registerStreamType(OV_TypeId_EBMLStream, "EBML stream", CIdentifier::undefined());
|
||||
m_typeManager->registerStreamType(OV_TypeId_ExperimentInfo, "Experiment information", OV_TypeId_EBMLStream);
|
||||
m_typeManager->registerStreamType(OV_TypeId_Stimulations, "Stimulations", OV_TypeId_EBMLStream);
|
||||
m_typeManager->registerStreamType(OV_TypeId_StreamedMatrix, "Streamed matrix", OV_TypeId_EBMLStream);
|
||||
m_typeManager->registerStreamType(OV_TypeId_ChannelLocalisation, "Channel localisation", OV_TypeId_StreamedMatrix);
|
||||
m_typeManager->registerStreamType(OV_TypeId_ChannelUnits, "Channel units", OV_TypeId_StreamedMatrix);
|
||||
m_typeManager->registerStreamType(OV_TypeId_FeatureVector, "Feature vector", OV_TypeId_StreamedMatrix);
|
||||
m_typeManager->registerStreamType(OV_TypeId_Signal, "Signal", OV_TypeId_StreamedMatrix);
|
||||
m_typeManager->registerStreamType(OV_TypeId_Spectrum, "Spectrum", OV_TypeId_StreamedMatrix);
|
||||
m_typeManager->registerStreamType(OV_TypeId_TimeFrequency, "Time-frequency", OV_TypeId_StreamedMatrix);
|
||||
m_typeManager->registerStreamType(OV_TypeId_CovarianceMatrix, "Covariance Matrix", OV_TypeId_StreamedMatrix);
|
||||
|
||||
|
||||
m_typeManager->registerType(OV_TypeId_Message, "Message");
|
||||
|
||||
m_scenarioManager.reset(new CScenarioManager(m_masterKernelCtx));
|
||||
m_pluginManager.reset(new CPluginManager(m_masterKernelCtx));
|
||||
m_metaboxManager.reset(new CMetaboxManager(m_masterKernelCtx));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKernelContext::uninitialize()
|
||||
{
|
||||
// As releaseScenario() can call into Plugin Manager we have to clear the scenario manager
|
||||
// before destroying the Plugin Manager. We can not destroy the Scenario Manager first
|
||||
// before Plugin Manager destructor needs it.
|
||||
CIdentifier scenarioID;
|
||||
while ((scenarioID = m_scenarioManager->getNextScenarioIdentifier(CIdentifier::undefined())) != CIdentifier::undefined())
|
||||
{
|
||||
m_scenarioManager->releaseScenario(scenarioID);
|
||||
}
|
||||
|
||||
CIdentifier algorithmIdentifier;
|
||||
while ((algorithmIdentifier = m_algorithmManager->getNextAlgorithmIdentifier(CIdentifier::undefined())) != CIdentifier::undefined())
|
||||
{
|
||||
m_algorithmManager->releaseAlgorithm(algorithmIdentifier);
|
||||
}
|
||||
|
||||
m_pluginManager.reset();
|
||||
m_metaboxManager.reset();
|
||||
m_scenarioManager.reset();
|
||||
m_typeManager.reset();
|
||||
m_playerManager.reset();
|
||||
m_algorithmManager.reset();
|
||||
m_configManager.reset();
|
||||
|
||||
this->getLogManager().removeListener(m_logListenerConsole.get());
|
||||
this->getLogManager().removeListener(m_logListenerFile.get());
|
||||
|
||||
m_logManager.reset();
|
||||
m_logListenerConsole.reset();
|
||||
m_logListenerFile.reset();
|
||||
|
||||
m_kernelObjectFactory.reset();
|
||||
|
||||
m_errorManager.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IAlgorithmManager& CKernelContext::getAlgorithmManager() const
|
||||
{
|
||||
assert(m_algorithmManager);
|
||||
return *m_algorithmManager;
|
||||
}
|
||||
|
||||
IConfigurationManager& CKernelContext::getConfigurationManager() const
|
||||
{
|
||||
assert(m_configManager);
|
||||
return *m_configManager;
|
||||
}
|
||||
|
||||
IKernelObjectFactory& CKernelContext::getKernelObjectFactory() const
|
||||
{
|
||||
assert(m_kernelObjectFactory);
|
||||
return *m_kernelObjectFactory;
|
||||
}
|
||||
|
||||
IPlayerManager& CKernelContext::getPlayerManager() const
|
||||
{
|
||||
assert(m_playerManager);
|
||||
return *m_playerManager;
|
||||
}
|
||||
|
||||
IPluginManager& CKernelContext::getPluginManager() const
|
||||
{
|
||||
assert(m_pluginManager);
|
||||
return *m_pluginManager;
|
||||
}
|
||||
|
||||
IMetaboxManager& CKernelContext::getMetaboxManager() const
|
||||
{
|
||||
assert(m_metaboxManager);
|
||||
return *m_metaboxManager;
|
||||
}
|
||||
|
||||
|
||||
IScenarioManager& CKernelContext::getScenarioManager() const
|
||||
{
|
||||
assert(m_scenarioManager);
|
||||
return *m_scenarioManager;
|
||||
}
|
||||
|
||||
ITypeManager& CKernelContext::getTypeManager() const
|
||||
{
|
||||
assert(m_typeManager);
|
||||
return *m_typeManager;
|
||||
}
|
||||
|
||||
ILogManager& CKernelContext::getLogManager() const
|
||||
{
|
||||
assert(m_logManager);
|
||||
return *m_logManager;
|
||||
}
|
||||
|
||||
IErrorManager& CKernelContext::getErrorManager() const
|
||||
{
|
||||
assert(m_errorManager);
|
||||
return *m_errorManager;
|
||||
}
|
||||
|
||||
ELogLevel CKernelContext::earlyGetLogLevel(const CString& rLogLevelName)
|
||||
{
|
||||
assert(m_logManager);
|
||||
|
||||
std::string value(rLogLevelName.toASCIIString());
|
||||
std::transform(value.begin(), value.end(), value.begin(), [](const char c) { return char(std::tolower(c)); });
|
||||
|
||||
if (value == "none") { return LogLevel_None; }
|
||||
if (value == "debug") { return LogLevel_Debug; }
|
||||
if (value == "benchmarking / profiling") { return LogLevel_Benchmark; }
|
||||
if (value == "trace") { return LogLevel_Trace; }
|
||||
if (value == "information") { return LogLevel_Info; }
|
||||
if (value == "warning") { return LogLevel_Warning; }
|
||||
if (value == "important warning") { return LogLevel_ImportantWarning; }
|
||||
if (value == "error") { return LogLevel_Error; }
|
||||
if (value == "fatal error") { return LogLevel_Fatal; }
|
||||
|
||||
OV_WARNING("Invalid log level " << rLogLevelName << " specified in configuration file, falling back to " << CString("Debug"), (*m_logManager));
|
||||
|
||||
return LogLevel_Debug;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CLogListenerConsole;
|
||||
class CLogListenerFile;
|
||||
|
||||
class CKernelContext final : public IKernelContext
|
||||
{
|
||||
public:
|
||||
|
||||
CKernelContext(const IKernelContext* masterKernelCtx, const CString& applicationName, const CString& configFile);
|
||||
~CKernelContext() override;
|
||||
bool initialize(const char* const * tokenList, size_t nToken) override;
|
||||
bool uninitialize() override;
|
||||
IAlgorithmManager& getAlgorithmManager() const override;
|
||||
IConfigurationManager& getConfigurationManager() const override;
|
||||
IKernelObjectFactory& getKernelObjectFactory() const override;
|
||||
IPlayerManager& getPlayerManager() const override;
|
||||
IPluginManager& getPluginManager() const override;
|
||||
IMetaboxManager& getMetaboxManager() const override;
|
||||
IScenarioManager& getScenarioManager() const override;
|
||||
ITypeManager& getTypeManager() const override;
|
||||
ILogManager& getLogManager() const override;
|
||||
IErrorManager& getErrorManager() const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(IKernelContext, OVK_ClassId_Kernel_KernelContext)
|
||||
|
||||
protected:
|
||||
|
||||
ELogLevel earlyGetLogLevel(const CString& rLogLevelName);
|
||||
|
||||
private:
|
||||
|
||||
const IKernelContext& m_masterKernelCtx;
|
||||
|
||||
std::unique_ptr<IAlgorithmManager> m_algorithmManager;
|
||||
std::unique_ptr<IConfigurationManager> m_configManager;
|
||||
std::unique_ptr<IKernelObjectFactory> m_kernelObjectFactory;
|
||||
std::unique_ptr<IPlayerManager> m_playerManager;
|
||||
std::unique_ptr<IPluginManager> m_pluginManager;
|
||||
std::unique_ptr<IMetaboxManager> m_metaboxManager;
|
||||
std::unique_ptr<IScenarioManager> m_scenarioManager;
|
||||
std::unique_ptr<ITypeManager> m_typeManager;
|
||||
std::unique_ptr<ILogManager> m_logManager;
|
||||
std::unique_ptr<IErrorManager> m_errorManager;
|
||||
|
||||
CString m_applicationName;
|
||||
CString m_configFile;
|
||||
|
||||
std::unique_ptr<CLogListenerConsole> m_logListenerConsole;
|
||||
std::unique_ptr<CLogListenerFile> m_logListenerFile;
|
||||
|
||||
CKernelContext() = delete;
|
||||
};
|
||||
|
||||
class CKernelContextBridge final : public IKernelContext
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CKernelContextBridge(const IKernelContext& ctx) : m_kernelCtx(ctx) { }
|
||||
|
||||
bool initialize() { return true; }
|
||||
bool uninitialize() override { return true; }
|
||||
|
||||
void setAlgorithmManager(IAlgorithmManager* manager) { m_algorithmManager = manager; }
|
||||
void setConfigurationManager(IConfigurationManager* manager) { m_configManager = manager; }
|
||||
void setKernelObjectFactory(IKernelObjectFactory* kernelObjectFactory) { m_kernelObjectFactory = kernelObjectFactory; }
|
||||
void setPlayerManager(IPlayerManager* manager) { m_playerManager = manager; }
|
||||
void setPluginManager(IPluginManager* manager) { m_pluginManager = manager; }
|
||||
void setMetaboxManager(IMetaboxManager* manager) { m_metaboxManager = manager; }
|
||||
void setScenarioManager(IScenarioManager* manager) { m_scenarioManager = manager; }
|
||||
void setTypeManager(ITypeManager* manager) { m_typeManager = manager; }
|
||||
void setLogManager(ILogManager* manager) { m_logManager = manager; }
|
||||
void setErrorManager(IErrorManager* manager) { m_errorManager = manager; }
|
||||
|
||||
IAlgorithmManager& getAlgorithmManager() const override { return m_algorithmManager ? *m_algorithmManager : m_kernelCtx.getAlgorithmManager(); }
|
||||
|
||||
IConfigurationManager& getConfigurationManager() const override { return m_configManager ? *m_configManager : m_kernelCtx.getConfigurationManager(); }
|
||||
|
||||
IKernelObjectFactory& getKernelObjectFactory() const override
|
||||
{
|
||||
return m_kernelObjectFactory ? *m_kernelObjectFactory : m_kernelCtx.getKernelObjectFactory();
|
||||
}
|
||||
|
||||
IPlayerManager& getPlayerManager() const override { return m_playerManager ? *m_playerManager : m_kernelCtx.getPlayerManager(); }
|
||||
IPluginManager& getPluginManager() const override { return m_pluginManager ? *m_pluginManager : m_kernelCtx.getPluginManager(); }
|
||||
IMetaboxManager& getMetaboxManager() const override { return m_metaboxManager ? *m_metaboxManager : m_kernelCtx.getMetaboxManager(); }
|
||||
IScenarioManager& getScenarioManager() const override { return m_scenarioManager ? *m_scenarioManager : m_kernelCtx.getScenarioManager(); }
|
||||
ITypeManager& getTypeManager() const override { return m_typeManager ? *m_typeManager : m_kernelCtx.getTypeManager(); }
|
||||
ILogManager& getLogManager() const override { return m_logManager ? *m_logManager : m_kernelCtx.getLogManager(); }
|
||||
IErrorManager& getErrorManager() const override { return m_errorManager ? *m_errorManager : m_kernelCtx.getErrorManager(); }
|
||||
|
||||
_IsDerivedFromClass_Final_(IKernelContext, OVK_ClassId_Kernel_KernelContext)
|
||||
|
||||
protected:
|
||||
|
||||
const IKernelContext& m_kernelCtx;
|
||||
|
||||
mutable IAlgorithmManager* m_algorithmManager = nullptr;
|
||||
mutable IConfigurationManager* m_configManager = nullptr;
|
||||
mutable IKernelObjectFactory* m_kernelObjectFactory = nullptr;
|
||||
mutable IPlayerManager* m_playerManager = nullptr;
|
||||
mutable IPluginManager* m_pluginManager = nullptr;
|
||||
mutable IMetaboxManager* m_metaboxManager = nullptr;
|
||||
mutable IScenarioManager* m_scenarioManager = nullptr;
|
||||
mutable ITypeManager* m_typeManager = nullptr;
|
||||
mutable ILogManager* m_logManager = nullptr;
|
||||
mutable IErrorManager* m_errorManager = nullptr;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#include "ovkCKernelObjectFactory.h"
|
||||
|
||||
#include "ovkCConfigurable.h"
|
||||
|
||||
#include "plugins/ovkCPluginModule.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
#define create(rcid,cid,sptr,cl) \
|
||||
if(rcid==cid) \
|
||||
{ \
|
||||
sptr=new cl(getKernelContext()); \
|
||||
if(sptr) { m_oCreatedObjects.push_back(sptr); } \
|
||||
}
|
||||
|
||||
IObject* CKernelObjectFactory::createObject(const CIdentifier& classID)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
IObject* res = nullptr;
|
||||
|
||||
create(classID, OV_ClassId_Kernel_Plugins_PluginModule, res, Kernel::CPluginModule);
|
||||
create(classID, OV_ClassId_Kernel_Configurable, res, Kernel::CConfigurable);
|
||||
|
||||
OV_ERROR_UNLESS_KRN(res, "Unable to allocate object with class id " << classID.str(), Kernel::ErrorType::BadAlloc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CKernelObjectFactory::releaseObject(IObject* pObject)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_oMutex);
|
||||
|
||||
if (!pObject) { return true; }
|
||||
|
||||
const CIdentifier classID = pObject->getClassIdentifier();
|
||||
|
||||
const auto i = find(m_oCreatedObjects.begin(), m_oCreatedObjects.end(), pObject);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(i != m_oCreatedObjects.end(),
|
||||
"Can not release object with final class id " << classID.str() << " - it is not owned by this fatory",
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
m_oCreatedObjects.erase(i);
|
||||
delete pObject;
|
||||
|
||||
this->getLogManager() << LogLevel_Debug << "Released object with final class id " << classID << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CKernelObjectFactory final : public TKernelObject<IKernelObjectFactory>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CKernelObjectFactory(const IKernelContext& ctx) : TKernelObject<IKernelObjectFactory>(ctx) {}
|
||||
IObject* createObject(const CIdentifier& classID) override;
|
||||
bool releaseObject(IObject* pObject) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IKernelObjectFactory>, OVK_ClassId_Kernel_KernelObjectFactory)
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<IObject*> m_oCreatedObjects;
|
||||
|
||||
std::mutex m_oMutex;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "ovkCObjectVisitorContext.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CObjectVisitorContext::CObjectVisitorContext(const IKernelContext& ctx) : TKernelObject<IObjectVisitorContext>(ctx) {}
|
||||
CObjectVisitorContext::~CObjectVisitorContext() {}
|
||||
|
||||
IAlgorithmManager& CObjectVisitorContext::getAlgorithmManager() const { return TKernelObject<IObjectVisitorContext>::getAlgorithmManager(); }
|
||||
IConfigurationManager& CObjectVisitorContext::getConfigurationManager() const { return TKernelObject<IObjectVisitorContext>::getConfigurationManager(); }
|
||||
ITypeManager& CObjectVisitorContext::getTypeManager() const { return TKernelObject<IObjectVisitorContext>::getTypeManager(); }
|
||||
ILogManager& CObjectVisitorContext::getLogManager() const { return TKernelObject<IObjectVisitorContext>::getLogManager(); }
|
||||
IErrorManager& CObjectVisitorContext::getErrorManager() const { return TKernelObject<IObjectVisitorContext>::getErrorManager(); }
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CObjectVisitorContext final : public TKernelObject<IObjectVisitorContext>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CObjectVisitorContext(const IKernelContext& ctx);
|
||||
~CObjectVisitorContext() override;
|
||||
IAlgorithmManager& getAlgorithmManager() const override;
|
||||
IConfigurationManager& getConfigurationManager() const override;
|
||||
ITypeManager& getTypeManager() const override;
|
||||
ILogManager& getLogManager() const override;
|
||||
IErrorManager& getErrorManager() const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IObjectVisitorContext>, OVK_ClassId_Kernel_ObjectVisitorContext)
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
#include "ovkTParameter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
#define _parameter_template_instance_simple_type_(_CName_, CType, IType, oClassId) \
|
||||
typedef TBaseParameter<TKernelObject<IParameter>, IType> _Base_##_CName_; \
|
||||
class _CName_ : public _Base_##_CName_ \
|
||||
{ \
|
||||
public: \
|
||||
_CName_(const IKernelContext& ctx, EParameterType eParameterType, const CIdentifier& subTypeID = CIdentifier::undefined()) \
|
||||
:TBaseParameter < TKernelObject < IParameter >, IType >(ctx, eParameterType, subTypeID) \
|
||||
{ \
|
||||
m_defaultValue = 0; \
|
||||
memcpy(&m_value, &m_defaultValue, sizeof(IType)); \
|
||||
} \
|
||||
_IsDerivedFromClass_Final_(_Base_##_CName_, oClassId) \
|
||||
protected: \
|
||||
CType m_defaultValue; \
|
||||
};
|
||||
|
||||
#define _parameter_template_instance_object_(_CName_, CType, IType, oClassId) \
|
||||
typedef TBaseParameter<TKernelObject<IParameter>, IType > _Base_##_CName_; \
|
||||
class _CName_ : public _Base_##_CName_ \
|
||||
{ \
|
||||
public: \
|
||||
_CName_(const IKernelContext& ctx, EParameterType eParameterType) \
|
||||
:TBaseParameter < TKernelObject < IParameter >, IType >(ctx, eParameterType) \
|
||||
{ \
|
||||
IType defaultValue=&m_defaultValue; \
|
||||
memcpy(&m_value, &defaultValue, sizeof(IType)); \
|
||||
} \
|
||||
_IsDerivedFromClass_Final_(_Base_##_CName_, oClassId) \
|
||||
protected: \
|
||||
CType m_defaultValue; \
|
||||
};
|
||||
|
||||
#define _parameter_template_instance_pointer_(_CName_, CType, IType, oClassId) \
|
||||
typedef TBaseParameter<TKernelObject<IParameter>, IType > _Base_##_CName_; \
|
||||
class _CName_ : public _Base_##_CName_ \
|
||||
{ \
|
||||
public: \
|
||||
_CName_(const IKernelContext& ctx, EParameterType eParameterType) \
|
||||
:TBaseParameter < TKernelObject < IParameter >, IType >(ctx, eParameterType) \
|
||||
{ \
|
||||
m_defaultValue = nullptr; \
|
||||
IType defaultValue=&m_defaultValue; \
|
||||
memcpy(&m_value, &defaultValue, sizeof(IType)); \
|
||||
} \
|
||||
_IsDerivedFromClass_Final_(_Base_##_CName_, oClassId) \
|
||||
protected: \
|
||||
CType m_defaultValue; \
|
||||
};
|
||||
|
||||
_parameter_template_instance_simple_type_(CIntegerParameter, int64_t, int64_t, OVK_ClassId_Kernel_IntegerParameter)
|
||||
|
||||
_parameter_template_instance_simple_type_(CUIntegerParameter, uint64_t, uint64_t, OVK_ClassId_Kernel_UIntegerParameter)
|
||||
|
||||
_parameter_template_instance_simple_type_(CEnumerationParameter, uint64_t, uint64_t, OVK_ClassId_Kernel_EnumerationParameter)
|
||||
|
||||
_parameter_template_instance_simple_type_(CBooleanParameter, bool, bool, OVK_ClassId_Kernel_BooleanParameter)
|
||||
|
||||
_parameter_template_instance_simple_type_(CFloatParameter, double, double, OVK_ClassId_Kernel_FloatParameter)
|
||||
|
||||
_parameter_template_instance_object_(CStringParameter, CString, CString*, OVK_ClassId_Kernel_StringParameter)
|
||||
|
||||
_parameter_template_instance_object_(CIdentifierParameter, CIdentifier, CIdentifier*, OVK_ClassId_Kernel_IdentifierParameter)
|
||||
|
||||
_parameter_template_instance_object_(CMatrixParameter, CMatrix, CMatrix*, OVK_ClassId_Kernel_MatrixParameter)
|
||||
|
||||
_parameter_template_instance_object_(CStimulationSetParameter, CStimulationSet, IStimulationSet*, OVK_ClassId_Kernel_StimulationSetParameter)
|
||||
|
||||
_parameter_template_instance_object_(CMemoryBufferParameter, CMemoryBuffer, IMemoryBuffer*, OVK_ClassId_Kernel_MemoryBufferParameter)
|
||||
|
||||
_parameter_template_instance_object_(CObjectParameter, CNullObject, IObject*, OVK_ClassId_Kernel_ObjectParameter)
|
||||
|
||||
_parameter_template_instance_pointer_(CPointerParameter, void*, void*, OVK_ClassId_Kernel_PointerParameter)
|
||||
|
||||
#undef _instance_
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,463 @@
|
||||
#include "ovkCTypeManager.h"
|
||||
|
||||
#include "lepton/Lepton.h"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
#define OV_TRACE_K(message) this->getLogManager() << OpenViBE::Kernel::LogLevel_Trace << message << "\n";
|
||||
#define OV_DEBUG_K(message) this->getLogManager() << OpenViBE::Kernel::LogLevel_Debug << message << "\n";
|
||||
#define OV_DEBUG_UNLESS_K(expression, message) if (!(expression)) { OV_DEBUG_K(message); }
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
struct SAInfB
|
||||
{
|
||||
bool operator()(const std::pair<CIdentifier, CString> a, const std::pair<CIdentifier, CString>& b) const { return a.second < b.second; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// because std::tolower has multiple signatures,
|
||||
// it can not be easily used in std::transform
|
||||
// this workaround is taken from http://www.gcek.net/ref/books/sw/cpp/ticppv2/
|
||||
template <class TCharT>
|
||||
static TCharT ToLower(TCharT c) { return std::tolower(c); }
|
||||
|
||||
CTypeManager::CTypeManager(const IKernelContext& ctx)
|
||||
: TKernelObject<ITypeManager>(ctx)
|
||||
{
|
||||
m_names[CIdentifier::undefined()] = "undefined";
|
||||
this->registerEnumerationType(OV_TypeId_BoxAlgorithmFlag, "BoxFlags");
|
||||
}
|
||||
|
||||
CIdentifier CTypeManager::getNextTypeIdentifier(const CIdentifier& previousID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
return getNextIdentifier<CString>(m_names, previousID);
|
||||
}
|
||||
|
||||
std::vector<std::pair<CIdentifier, CString>> CTypeManager::getSortedTypes() const
|
||||
{
|
||||
std::vector<std::pair<CIdentifier, CString>> sorted;
|
||||
|
||||
for (const auto& element : m_names) { sorted.push_back(std::pair<CIdentifier, CString>(element.first, element.second)); }
|
||||
std::sort(sorted.begin(), sorted.end(), SAInfB());
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
bool CTypeManager::registerType(const CIdentifier& typeID, const CString& name)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!isRegistered(typeID), "Trying to register type " << typeID.str() << " that already exists.",
|
||||
ErrorType::BadArgument);
|
||||
|
||||
OV_DEBUG_UNLESS_K(m_takenNames.find(name) == m_takenNames.end(),
|
||||
"Trying to register type " << typeID << " with a name that already exists ( " << name << ")");
|
||||
|
||||
m_names[typeID] = name;
|
||||
OV_TRACE_K("Registered type id " << typeID << " - " << name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTypeManager::registerStreamType(const CIdentifier& typeID, const CString& name, const CIdentifier& parentTypeID)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!isRegistered(typeID), "Trying to register stream type " << typeID.str() << " that already exists.",
|
||||
ErrorType::BadArgument);
|
||||
|
||||
OV_DEBUG_UNLESS_K(m_takenNames.find(name) == m_takenNames.end(),
|
||||
"Trying to register stream type " << typeID << " with a name that already exists ( " << name << ")");
|
||||
|
||||
OV_ERROR_UNLESS_KRF(parentTypeID == CIdentifier::undefined() || isStream(parentTypeID),
|
||||
"Trying to register an invalid stream type [" << name << "] " << typeID.str() << ", parent : " << parentTypeID.str() << ".",
|
||||
ErrorType::BadArgument);
|
||||
|
||||
m_names[typeID] = name;
|
||||
m_takenNames.insert(name);
|
||||
m_streams[typeID] = parentTypeID;
|
||||
OV_TRACE_K("Registered stream type id " << typeID << "::" << parentTypeID << " - " << name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTypeManager::registerEnumerationType(const CIdentifier& typeID, const CString& name)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
if (isRegistered(typeID))
|
||||
{
|
||||
if (m_names[typeID] != name)
|
||||
{
|
||||
OV_ERROR_KRF(
|
||||
"Trying to register enum type " << typeID.str() << " that already exists with different value (" << m_names[typeID] << " != " << name <<
|
||||
")",
|
||||
ErrorType::BadArgument);
|
||||
}
|
||||
OV_DEBUG_K("Trying to register enum type " << typeID.str() << " that already exists.");
|
||||
}
|
||||
|
||||
OV_DEBUG_UNLESS_K(m_takenNames.find(name) == m_takenNames.end(),
|
||||
"Trying to register enum type " << typeID << " with a name that already exists ( " << name << ")");
|
||||
|
||||
m_names[typeID] = name;
|
||||
m_takenNames.insert(name);
|
||||
m_enumerations[typeID];
|
||||
OV_TRACE_K("Registered enumeration type id " << typeID << " - " << name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTypeManager::registerEnumerationEntry(const CIdentifier& typeID, const CString& name, const uint64_t value)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto itEnumeration = m_enumerations.find(typeID);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(itEnumeration != m_enumerations.end(), "Enumeration type [" << typeID.str() << "] does not exist." << name,
|
||||
ErrorType::BadArgument);
|
||||
|
||||
const auto itElem = itEnumeration->second.find(value);
|
||||
if (itElem != itEnumeration->second.end())
|
||||
{
|
||||
if (std::string(itElem->second) != std::string(name))
|
||||
{
|
||||
OV_WARNING_K(
|
||||
"Enumeration type [" + typeID.str() + "] already has element [" + std::to_string(value) + "]. Value will be overriden : "
|
||||
+ itElem->second.toASCIIString() + " => " + name.toASCIIString());
|
||||
}
|
||||
else { OV_DEBUG_K("Enumeration type [" << typeID.str() << "] already has element [" << value << "]."); }
|
||||
}
|
||||
|
||||
itEnumeration->second[value] = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTypeManager::registerBitMaskType(const CIdentifier& typeID, const CString& name)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!isRegistered(typeID), "Trying to register bitmask type " << typeID.str() << " that already exists.",
|
||||
ErrorType::BadArgument);
|
||||
|
||||
OV_DEBUG_UNLESS_K(m_takenNames.find(name) == m_takenNames.end(),
|
||||
"Trying to register bitmask type " << typeID << " with a name that already exists ( " << name << ")");
|
||||
|
||||
m_names[typeID] = name;
|
||||
m_bitMasks[typeID];
|
||||
OV_TRACE_K("Registered bitmask type id " << typeID << " - " << name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTypeManager::registerBitMaskEntry(const CIdentifier& typeID, const CString& name, const uint64_t value)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto itBitMask = m_bitMasks.find(typeID);
|
||||
OV_ERROR_UNLESS_KRF(itBitMask != m_bitMasks.end(), "Bitmask type [" << typeID.str() << "] does not exist.", Kernel::ErrorType::BadArgument);
|
||||
|
||||
const auto itElem = itBitMask->second.find(value);
|
||||
if (itElem != itBitMask->second.end())
|
||||
{
|
||||
if (std::string(itElem->second) != std::string(name))
|
||||
{
|
||||
OV_WARNING_K(
|
||||
"Bitmask type [" + typeID.str() + "] already has element [" + std::to_string(value) + "]. Value will be overriden : "
|
||||
+ itElem->second.toASCIIString() + " => " + name.toASCIIString());
|
||||
}
|
||||
else { OV_DEBUG_K("Bitmask type [" << typeID.str() << "] already has element [" << value << "]."); }
|
||||
}
|
||||
|
||||
for (size_t nBit = 0, i = 0; i < 64; ++i)
|
||||
{
|
||||
if (value & (1LL << i))
|
||||
{
|
||||
nBit++;
|
||||
OV_ERROR_UNLESS_KRF(nBit <= 1,
|
||||
"Discarded bitmask entry (" << m_names[typeID] << ":" << name << ") because value " << value << " contains more than one bit",
|
||||
ErrorType::Overflow);
|
||||
}
|
||||
}
|
||||
itBitMask->second[value] = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTypeManager::isRegistered(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
return m_names.find(typeID) != m_names.end();
|
||||
}
|
||||
|
||||
bool CTypeManager::isStream(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
return m_streams.find(typeID) != m_streams.end();
|
||||
}
|
||||
|
||||
bool CTypeManager::isDerivedFromStream(const CIdentifier& typeID, const CIdentifier& parentTypeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto it = m_streams.find(typeID);
|
||||
const auto itParent = m_streams.find(parentTypeID);
|
||||
if (it == m_streams.end() || itParent == m_streams.end()) { return false; }
|
||||
while (it != m_streams.end())
|
||||
{
|
||||
if (it->first == parentTypeID) { return true; }
|
||||
it = m_streams.find(it->second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CTypeManager::isEnumeration(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
return m_enumerations.find(typeID) != m_enumerations.end();
|
||||
}
|
||||
|
||||
bool CTypeManager::isBitMask(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
return m_bitMasks.find(typeID) != m_bitMasks.end();
|
||||
}
|
||||
|
||||
CString CTypeManager::getTypeName(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
if (!isRegistered(typeID)) { return CString(""); }
|
||||
return m_names.find(typeID)->second;
|
||||
}
|
||||
|
||||
CIdentifier CTypeManager::getStreamParentType(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
if (!isStream(typeID)) { return CIdentifier::undefined(); }
|
||||
return m_streams.find(typeID)->second;
|
||||
}
|
||||
|
||||
size_t CTypeManager::getEnumerationEntryCount(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto itEnumeration = m_enumerations.find(typeID);
|
||||
if (itEnumeration == m_enumerations.end()) { return 0; }
|
||||
return itEnumeration->second.size();
|
||||
}
|
||||
|
||||
bool CTypeManager::getEnumerationEntry(const CIdentifier& typeID, const uint64_t index, CString& name, uint64_t& value) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_enumerations.find(typeID);
|
||||
if (it == m_enumerations.end()) { return false; }
|
||||
|
||||
if (index >= it->second.size()) { return false; }
|
||||
|
||||
auto itEntry = it->second.begin();
|
||||
for (size_t i = 0; i < index && itEntry != it->second.end(); i++, ++itEntry) { }
|
||||
|
||||
value = itEntry->first;
|
||||
name = itEntry->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
CString CTypeManager::getEnumerationEntryNameFromValue(const CIdentifier& typeID, const uint64_t value) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_enumerations.find(typeID);
|
||||
if (it == m_enumerations.end()) { return ""; }
|
||||
const auto itEntry = it->second.find(value);
|
||||
if (itEntry == it->second.end()) { return ""; }
|
||||
return it->second.find(value)->second;
|
||||
}
|
||||
|
||||
uint64_t CTypeManager::getEnumerationEntryValueFromName(const CIdentifier& typeID, const CString& name) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_enumerations.find(typeID);
|
||||
if (it == m_enumerations.end()) { return OV_IncorrectStimulation; }
|
||||
|
||||
// first looks at the exact std::string match
|
||||
for (const auto& entry : it->second) { if (entry.second == name) { return entry.first; } }
|
||||
|
||||
// then looks at the caseless std::string match
|
||||
std::string nameLower = name.toASCIIString();
|
||||
std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ToLower<std::string::value_type>);
|
||||
for (const auto& entry : it->second)
|
||||
{
|
||||
std::string tmp = entry.second.toASCIIString();
|
||||
std::transform(tmp.begin(), tmp.end(), tmp.begin(), ToLower<std::string::value_type>);
|
||||
if (tmp == nameLower) { return entry.first; }
|
||||
}
|
||||
|
||||
// then looks at the std::string being the value itself
|
||||
try
|
||||
{
|
||||
const uint64_t value = std::stoull(name.toASCIIString());
|
||||
|
||||
if ((it->second.find(value) != it->second.end()) ||
|
||||
(typeID == OV_TypeId_Stimulation && this->getConfigurationManager().expandAsBoolean("Kernel_AllowUnregisteredNumericalStimulationIdentifiers")))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
catch (const std::exception&) { return OV_IncorrectStimulation; }
|
||||
|
||||
return OV_IncorrectStimulation;
|
||||
}
|
||||
|
||||
size_t CTypeManager::getBitMaskEntryCount(const CIdentifier& typeID) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto itBitMask = m_bitMasks.find(typeID);
|
||||
if (itBitMask == m_bitMasks.end()) { return 0; }
|
||||
return itBitMask->second.size();
|
||||
}
|
||||
|
||||
bool CTypeManager::getBitMaskEntry(const CIdentifier& typeID, const uint64_t index, CString& name, uint64_t& value) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto itBitMask = m_bitMasks.find(typeID);
|
||||
if (itBitMask == m_bitMasks.end()) { return false; }
|
||||
|
||||
if (index >= itBitMask->second.size()) { return false; }
|
||||
|
||||
auto itBitMaskEntry = itBitMask->second.begin();
|
||||
for (size_t i = 0; i < index && itBitMaskEntry != itBitMask->second.end(); i++, ++itBitMaskEntry) { }
|
||||
|
||||
value = itBitMaskEntry->first;
|
||||
name = itBitMaskEntry->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
CString CTypeManager::getBitMaskEntryNameFromValue(const CIdentifier& typeID, const uint64_t value) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto itBitMask = m_bitMasks.find(typeID);
|
||||
if (itBitMask == m_bitMasks.end()) { return ""; }
|
||||
const auto itBitMaskEntry = itBitMask->second.find(value);
|
||||
if (itBitMaskEntry == itBitMask->second.end()) { return ""; }
|
||||
return itBitMask->second.find(value)->second;
|
||||
}
|
||||
|
||||
uint64_t CTypeManager::getBitMaskEntryValueFromName(const CIdentifier& typeID, const CString& name) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto itBitMask = m_bitMasks.find(typeID);
|
||||
if (itBitMask == m_bitMasks.end()) { return 0xffffffffffffffffLL; }
|
||||
|
||||
// first looks at the exact std::string match
|
||||
for (const auto& mask : itBitMask->second) { if (mask.second == name) { return mask.first; } }
|
||||
|
||||
// then looks at the caseless std::string match
|
||||
std::string entryNameLower = name.toASCIIString();
|
||||
std::transform(entryNameLower.begin(), entryNameLower.end(), entryNameLower.begin(), ToLower<std::string::value_type>);
|
||||
for (const auto& mask : itBitMask->second)
|
||||
{
|
||||
std::string itEntryNameLower = mask.second.toASCIIString();
|
||||
std::transform(itEntryNameLower.begin(), itEntryNameLower.end(), itEntryNameLower.begin(), ToLower<std::string::value_type>);
|
||||
if (itEntryNameLower == entryNameLower) { return mask.first; }
|
||||
}
|
||||
|
||||
// then looks at the std::string being the value itself
|
||||
try
|
||||
{
|
||||
const uint64_t value = std::stoll(name.toASCIIString());
|
||||
if (itBitMask->second.find(value) != itBitMask->second.end()) { return value; }
|
||||
}
|
||||
catch (const std::exception&) { return 0xffffffffffffffffLL; }
|
||||
|
||||
return 0xffffffffffffffffLL;
|
||||
}
|
||||
|
||||
CString CTypeManager::getBitMaskEntryCompositionNameFromValue(const CIdentifier& typeID, const uint64_t value) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto itBitMask = m_bitMasks.find(typeID);
|
||||
if (itBitMask == m_bitMasks.end()) { return ""; }
|
||||
|
||||
std::string res;
|
||||
for (size_t i = 0; i < 64; ++i)
|
||||
{
|
||||
if (value & (1LL << i))
|
||||
{
|
||||
const auto itBitMaskEntry = itBitMask->second.find(value & (1LL << i));
|
||||
if (itBitMaskEntry == itBitMask->second.end()) { return ""; }
|
||||
if (res.empty()) { res = itBitMaskEntry->second.toASCIIString(); }
|
||||
else
|
||||
{
|
||||
res += std::string(1, OV_Value_EnumeratedStringSeparator);
|
||||
res += itBitMaskEntry->second.toASCIIString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return CString(res.c_str());
|
||||
}
|
||||
|
||||
uint64_t CTypeManager::getBitMaskEntryCompositionValueFromName(const CIdentifier& typeID, const CString& name) const
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
const auto it = m_bitMasks.find(typeID);
|
||||
if (it == m_bitMasks.end()) { return 0; }
|
||||
|
||||
uint64_t res = 0;
|
||||
const std::string entryCompositionName = name.toASCIIString();
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
do
|
||||
{
|
||||
i = entryCompositionName.find(OV_Value_EnumeratedStringSeparator, i);
|
||||
if (i == std::string::npos) { i = entryCompositionName.length(); }
|
||||
|
||||
if (i != j)
|
||||
{
|
||||
std::string entryName;
|
||||
entryName.assign(entryCompositionName, j, i - j);
|
||||
|
||||
bool found = false;
|
||||
for (const auto& mask : it->second)
|
||||
{
|
||||
if (mask.second == CString(entryName.c_str()))
|
||||
{
|
||||
res |= mask.first;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) { return 0; }
|
||||
}
|
||||
|
||||
i++;
|
||||
j = i;
|
||||
} while (i < entryCompositionName.length());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CTypeManager::evaluateSettingValue(const CString value, double& result) const
|
||||
{
|
||||
// parse and expression with no variables or functions
|
||||
try { result = Lepton::Parser::parse(value.toASCIIString()).evaluate(); }
|
||||
catch (...) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CTypeManager final : public TKernelObject<ITypeManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CTypeManager(const IKernelContext& ctx);
|
||||
CIdentifier getNextTypeIdentifier(const CIdentifier& previousID) const override;
|
||||
std::vector<std::pair<CIdentifier, CString>> getSortedTypes() const override;
|
||||
bool registerType(const CIdentifier& typeID, const CString& name) override;
|
||||
bool registerStreamType(const CIdentifier& typeID, const CString& name, const CIdentifier& parentTypeID) override;
|
||||
bool registerEnumerationType(const CIdentifier& typeID, const CString& name) override;
|
||||
bool registerEnumerationEntry(const CIdentifier& typeID, const CString& name, uint64_t value) override;
|
||||
bool registerBitMaskType(const CIdentifier& typeID, const CString& name) override;
|
||||
bool registerBitMaskEntry(const CIdentifier& typeID, const CString& name, uint64_t value) override;
|
||||
bool isRegistered(const CIdentifier& typeID) const override;
|
||||
bool isStream(const CIdentifier& typeID) const override;
|
||||
bool isDerivedFromStream(const CIdentifier& typeID, const CIdentifier& parentTypeID) const override;
|
||||
bool isEnumeration(const CIdentifier& typeID) const override;
|
||||
bool isBitMask(const CIdentifier& typeID) const override;
|
||||
CString getTypeName(const CIdentifier& typeID) const override;
|
||||
CIdentifier getStreamParentType(const CIdentifier& typeID) const override;
|
||||
size_t getEnumerationEntryCount(const CIdentifier& typeID) const override;
|
||||
bool getEnumerationEntry(const CIdentifier& typeID, uint64_t index, CString& name, uint64_t& value) const override;
|
||||
CString getEnumerationEntryNameFromValue(const CIdentifier& typeID, uint64_t value) const override;
|
||||
uint64_t getEnumerationEntryValueFromName(const CIdentifier& typeID, const CString& name) const override;
|
||||
size_t getBitMaskEntryCount(const CIdentifier& typeID) const override;
|
||||
bool getBitMaskEntry(const CIdentifier& typeID, uint64_t index, CString& name, uint64_t& value) const override;
|
||||
CString getBitMaskEntryNameFromValue(const CIdentifier& typeID, uint64_t value) const override;
|
||||
uint64_t getBitMaskEntryValueFromName(const CIdentifier& typeID, const CString& name) const override;
|
||||
CString getBitMaskEntryCompositionNameFromValue(const CIdentifier& typeID, uint64_t value) const override;
|
||||
uint64_t getBitMaskEntryCompositionValueFromName(const CIdentifier& typeID, const CString& name) const override;
|
||||
bool evaluateSettingValue(CString value, double& result) const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<ITypeManager>, OVK_ClassId_Kernel_TypeManager)
|
||||
|
||||
protected:
|
||||
|
||||
std::map<CIdentifier, CString> m_names;
|
||||
std::set<CString> m_takenNames;
|
||||
std::map<CIdentifier, std::map<uint64_t, CString>> m_enumerations;
|
||||
std::map<CIdentifier, std::map<uint64_t, CString>> m_bitMasks;
|
||||
std::map<CIdentifier, CIdentifier> m_streams;
|
||||
|
||||
mutable std::recursive_mutex m_mutex;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
|
||||
#include "ovkCParameter.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class IParameter;
|
||||
|
||||
template <class TBase>
|
||||
class TBaseConfigurable : public TBase
|
||||
{
|
||||
public:
|
||||
|
||||
explicit TBaseConfigurable(const IKernelContext& ctx) : TBase(ctx) { }
|
||||
|
||||
~TBaseConfigurable() override
|
||||
{
|
||||
auto itParameter = m_parameters.begin();
|
||||
while (itParameter != m_parameters.end())
|
||||
{
|
||||
// @FIXME is this really as intended, test the first, delete the second?
|
||||
if (itParameter->second.first)
|
||||
{
|
||||
delete itParameter->second.second;
|
||||
itParameter->second.second = nullptr;
|
||||
}
|
||||
++itParameter;
|
||||
}
|
||||
}
|
||||
|
||||
CIdentifier getNextParameterIdentifier(const CIdentifier& previousID) const override
|
||||
{
|
||||
return getNextIdentifier<std::pair<bool, IParameter*>>(m_parameters, previousID);
|
||||
}
|
||||
|
||||
IParameter* getParameter(const CIdentifier& parameterID) override
|
||||
{
|
||||
const auto it = m_parameters.find(parameterID);
|
||||
if (it == m_parameters.end()) { return nullptr; }
|
||||
return it->second.second;
|
||||
}
|
||||
|
||||
bool setParameter(const CIdentifier& parameterID, IParameter& parameter) override
|
||||
{
|
||||
this->removeParameter(parameterID);
|
||||
|
||||
m_parameters[parameterID] = std::pair<bool, IParameter*>(false, ¶meter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IParameter* createParameter(const CIdentifier& parameterID, const EParameterType parameterType, const CIdentifier& subTypeID) override
|
||||
{
|
||||
const auto it = m_parameters.find(parameterID);
|
||||
if (it != m_parameters.end()) { return nullptr; }
|
||||
|
||||
IParameter* parameter = nullptr;
|
||||
switch (parameterType)
|
||||
{
|
||||
case ParameterType_UInteger: parameter = new CUIntegerParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_Integer: parameter = new CIntegerParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_Enumeration: parameter = new CEnumerationParameter(this->getKernelContext(), parameterType, subTypeID);
|
||||
break;
|
||||
case ParameterType_Boolean: parameter = new CBooleanParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_Float: parameter = new CFloatParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_String: parameter = new CStringParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_Identifier: parameter = new CIdentifierParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_Matrix: parameter = new CMatrixParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_StimulationSet: parameter = new CStimulationSetParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_MemoryBuffer: parameter = new CMemoryBufferParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_Object: parameter = new CObjectParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
case ParameterType_None:
|
||||
case ParameterType_Pointer: parameter = new CPointerParameter(this->getKernelContext(), parameterType);
|
||||
break;
|
||||
}
|
||||
|
||||
if (parameter != nullptr) { m_parameters[parameterID] = std::pair<bool, IParameter*>(true, parameter); }
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
bool removeParameter(const CIdentifier& rParameterIdentifier) override
|
||||
{
|
||||
auto itParameter = m_parameters.find(rParameterIdentifier);
|
||||
if (itParameter == m_parameters.end()) { return false; }
|
||||
|
||||
if (itParameter->second.first) { delete itParameter->second.second; }
|
||||
m_parameters.erase(itParameter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(TBase, OVK_ClassId_Kernel_ConfigurableT)
|
||||
|
||||
private:
|
||||
|
||||
std::map<CIdentifier, std::pair<bool, IParameter*>> m_parameters;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovk_base.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
template <class T>
|
||||
class TKernelObject : public T
|
||||
{
|
||||
public:
|
||||
virtual ~TKernelObject() = default;
|
||||
|
||||
explicit TKernelObject(const IKernelContext& ctx) : m_kernelCtx(ctx) { }
|
||||
|
||||
TKernelObject(const TKernelObject&) = delete;
|
||||
TKernelObject& operator=(const TKernelObject&) = delete;
|
||||
|
||||
const IKernelContext& getKernelContext() const { return m_kernelCtx; }
|
||||
virtual IAlgorithmManager& getAlgorithmManager() const { return m_kernelCtx.getAlgorithmManager(); }
|
||||
virtual IConfigurationManager& getConfigurationManager() const { return m_kernelCtx.getConfigurationManager(); }
|
||||
virtual IKernelObjectFactory& getKernelObjectFactory() const { return m_kernelCtx.getKernelObjectFactory(); }
|
||||
virtual IPlayerManager& getPlayerManager() const { return m_kernelCtx.getPlayerManager(); }
|
||||
virtual IPluginManager& getPluginManager() const { return m_kernelCtx.getPluginManager(); }
|
||||
virtual IMetaboxManager& getMetaboxManager() const { return m_kernelCtx.getMetaboxManager(); }
|
||||
virtual IScenarioManager& getScenarioManager() const { return m_kernelCtx.getScenarioManager(); }
|
||||
virtual ITypeManager& getTypeManager() const { return m_kernelCtx.getTypeManager(); }
|
||||
virtual ILogManager& getLogManager() const { return m_kernelCtx.getLogManager(); }
|
||||
virtual IErrorManager& getErrorManager() const { return m_kernelCtx.getErrorManager(); }
|
||||
|
||||
_IsDerivedFromClass_(T, OVK_ClassId_Kernel_KernelObjectT)
|
||||
|
||||
private:
|
||||
|
||||
const IKernelContext& m_kernelCtx;
|
||||
|
||||
// TKernelObject();
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkTKernelObject.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
template <class TBase, class TType>
|
||||
class TBaseParameter : public TBase
|
||||
{
|
||||
public:
|
||||
|
||||
TBaseParameter(const IKernelContext& ctx, const EParameterType type, const CIdentifier& subTypeID = CIdentifier::undefined())
|
||||
: TBase(ctx), m_valueRef(nullptr), m_value(0), m_parameterType(type), m_subTypeID(subTypeID) { }
|
||||
|
||||
uint64_t getParameterSize() const override { return sizeof(TType); }
|
||||
EParameterType getType() const override { return m_parameterType; }
|
||||
CIdentifier getSubTypeIdentifier() const override { return m_subTypeID; }
|
||||
|
||||
bool clearReferenceTarget() override
|
||||
{
|
||||
m_valueRef = NULL;
|
||||
m_parameterRef = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getReferenceTarget(IParameter*& pParameterRef) const override
|
||||
{
|
||||
pParameterRef = m_parameterRef;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setReferenceTarget(IParameter* pParameterRef) override
|
||||
{
|
||||
if (m_valueRef) { m_valueRef = NULL; }
|
||||
m_parameterRef = pParameterRef;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getReferenceTarget(void* pValue) const override
|
||||
{
|
||||
memcpy(&pValue, &m_valueRef, sizeof(TType*));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setReferenceTarget(const void* pValue) override
|
||||
{
|
||||
if (m_parameterRef) { m_parameterRef = nullptr; }
|
||||
memcpy(&m_valueRef, &pValue, sizeof(TType*));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getValue(void* pValue) const override
|
||||
{
|
||||
if (m_parameterRef) { return m_parameterRef->getValue(pValue); }
|
||||
if (m_valueRef) { memcpy(pValue, m_valueRef, sizeof(TType)); }
|
||||
else { memcpy(pValue, &m_value, sizeof(TType)); }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setValue(const void* pValue) override
|
||||
{
|
||||
if (m_parameterRef) { return m_parameterRef->setValue(pValue); }
|
||||
if (m_valueRef) { memcpy(m_valueRef, pValue, sizeof(TType)); }
|
||||
else { memcpy(&m_value, pValue, sizeof(TType)); }
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_(TBase, OVK_ClassId_Kernel_ParameterT)
|
||||
|
||||
protected:
|
||||
|
||||
IParameter* m_parameterRef = nullptr;
|
||||
TType* m_valueRef = nullptr;
|
||||
TType m_value;
|
||||
EParameterType m_parameterType;
|
||||
CIdentifier m_subTypeID = CIdentifier::undefined();
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "ovkCBoxAlgorithmContext.h"
|
||||
#include "ovkCPlayerContext.h"
|
||||
#include "ovkCSimulatedBox.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CBoxAlgorithmCtx::CBoxAlgorithmCtx(const IKernelContext& ctx, CSimulatedBox* simulatedBox, const IBox* box)
|
||||
: TKernelObject<IBoxAlgorithmContext>(ctx), m_pStaticBoxContext(box), m_pDynamicBoxContext(simulatedBox), m_oPlayerContext(ctx, simulatedBox) {}
|
||||
|
||||
|
||||
bool CBoxAlgorithmCtx::markAlgorithmAsReadyToProcess()
|
||||
{
|
||||
m_bReadyToProcess = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
#include "ovkCPlayerContext.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CSimulatedBox;
|
||||
|
||||
class CBoxAlgorithmCtx final : public TKernelObject<IBoxAlgorithmContext>
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxAlgorithmCtx(const IKernelContext& ctx, CSimulatedBox* simulatedBox, const IBox* box);
|
||||
~CBoxAlgorithmCtx() override {}
|
||||
const IBox* getStaticBoxContext() override { return m_pStaticBoxContext; }
|
||||
IBoxIO* getDynamicBoxContext() override { return m_pDynamicBoxContext; }
|
||||
IPlayerContext* getPlayerContext() override { return &m_oPlayerContext; }
|
||||
bool markAlgorithmAsReadyToProcess() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IBoxAlgorithmContext>, OVK_ClassId_Kernel_Player_BoxAlgorithmContext)
|
||||
|
||||
bool isAlgorithmReadyToProcess() const { return m_bReadyToProcess; }
|
||||
|
||||
protected:
|
||||
|
||||
const IBox* m_pStaticBoxContext = nullptr;
|
||||
IBoxIO* m_pDynamicBoxContext = nullptr;
|
||||
// here we prefer value type over reference/pointer
|
||||
// in order to improve performance at runtime (no heap allocation)
|
||||
CPlayerContext m_oPlayerContext;
|
||||
bool m_bReadyToProcess = false;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#include "ovkCPlayerContext.h"
|
||||
#include "ovkCSimulatedBox.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
void CBoxAlgorithmLogManager::log(const ELogLevel logLevel)
|
||||
{
|
||||
CIdentifier boxId;
|
||||
m_simulatedBox.getBoxIdentifier(boxId);
|
||||
|
||||
m_logManager << logLevel << "At time " << CTime(m_playerCtx.getCurrentTime()) << " <" << LogColor_PushStateBit << LogColor_ForegroundBlue
|
||||
<< "Box algorithm" << LogColor_PopStateBit << "::" << boxId << " aka " << m_simulatedBox.getName() << "> ";
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
class CSimulatedBox;
|
||||
|
||||
class CBoxAlgorithmLogManager final : public ILogManager
|
||||
{
|
||||
public:
|
||||
CBoxAlgorithmLogManager(const IPlayerContext& playerContext, ILogManager& logManager, CSimulatedBox& simulatedBox)
|
||||
: m_playerCtx(playerContext), m_logManager(logManager), m_simulatedBox(simulatedBox) {}
|
||||
|
||||
bool isActive(const ELogLevel level) override { return m_logManager.isActive(level); }
|
||||
bool activate(const ELogLevel level, const bool active) override { return m_logManager.activate(level, active); }
|
||||
|
||||
bool activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active) override
|
||||
{
|
||||
return m_logManager.activate(startLevel, endLevel, active);
|
||||
}
|
||||
|
||||
bool activate(const bool active) override { return m_logManager.activate(active); }
|
||||
|
||||
bool addListener(ILogListener* listener) override { return m_logManager.addListener(listener); }
|
||||
bool removeListener(ILogListener* listener) override { return m_logManager.removeListener(listener); }
|
||||
|
||||
void log(const CTime value) override { m_logManager.log(value); }
|
||||
void log(const uint64_t value) override { m_logManager.log(value); }
|
||||
void log(const uint32_t value) override { m_logManager.log(value); }
|
||||
void log(const int64_t value) override { m_logManager.log(value); }
|
||||
void log(const int value) override { m_logManager.log(value); }
|
||||
void log(const double value) override { m_logManager.log(value); }
|
||||
void log(const bool value) override { m_logManager.log(value); }
|
||||
void log(const CString& value) override { m_logManager.log(value); }
|
||||
void log(const std::string& value) override { m_logManager.log(value); }
|
||||
void log(const char* value) override { m_logManager.log(value); }
|
||||
void log(const CIdentifier& value) override { m_logManager.log(value); }
|
||||
void log(const ELogColor value) override { m_logManager.log(value); }
|
||||
void log(const ELogLevel logLevel) override;
|
||||
|
||||
CIdentifier getClassIdentifier() const override { return CIdentifier(); }
|
||||
|
||||
private:
|
||||
const IPlayerContext& m_playerCtx;
|
||||
ILogManager& m_logManager;
|
||||
CSimulatedBox& m_simulatedBox;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
#include "ovkCBoxSettingModifierVisitor.h"
|
||||
|
||||
#include "ovkCPlayer.h"
|
||||
|
||||
#include <xml/IReader.h>
|
||||
#include <fs/Files.h>
|
||||
#include "../../tools/ovk_setting_checker.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define OVD_AttributeId_SettingOverrideFilename OpenViBE::CIdentifier(0x8D21FF41, 0xDF6AFE7E)
|
||||
#define OV_AttributeId_Box_Disabled OpenViBE::CIdentifier(0x341D3912, 0x1478DE86)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
void CBoxSettingModifierVisitor::openChild(const char* name, const char** /*sAttributeName*/, const char** /*sAttributeValue*/, const size_t /*nAttribute*/)
|
||||
{
|
||||
if (!m_IsParsingSettingOverride) { if (std::string(name) == std::string("OpenViBE-SettingsOverride")) { m_IsParsingSettingOverride = true; } }
|
||||
else if (std::string(name) == std::string("SettingValue")) { m_IsParsingSettingValue = true; }
|
||||
else { m_IsParsingSettingValue = false; }
|
||||
}
|
||||
|
||||
void CBoxSettingModifierVisitor::processChildData(const char* data)
|
||||
{
|
||||
if (m_IsParsingSettingValue)
|
||||
{
|
||||
m_ObjectVisitorCtx->getLogManager() << LogLevel_Debug << "Using [" << data << "] as setting " << m_SettingIdx << "...\n";
|
||||
m_Box->setSettingValue(m_SettingIdx, data);
|
||||
}
|
||||
}
|
||||
|
||||
void CBoxSettingModifierVisitor::closeChild()
|
||||
{
|
||||
//We need to count it here because we need to take in account the empty value
|
||||
if (m_IsParsingSettingValue) { m_SettingIdx++; }
|
||||
m_IsParsingSettingValue = false;
|
||||
}
|
||||
|
||||
bool CBoxSettingModifierVisitor::processBegin(IObjectVisitorContext& visitorCtx, IBox& box)
|
||||
{
|
||||
m_ObjectVisitorCtx = &visitorCtx;
|
||||
|
||||
// checks if this box should override
|
||||
// settings from external file
|
||||
if (box.hasAttribute(OVD_AttributeId_SettingOverrideFilename))
|
||||
{
|
||||
const CString settingOverrideFilename = box.getAttributeValue(OVD_AttributeId_SettingOverrideFilename);
|
||||
CString settingOverrideFilenameFinal;
|
||||
if (m_ConfigManager == nullptr) { settingOverrideFilenameFinal = visitorCtx.getConfigurationManager().expand(settingOverrideFilename); }
|
||||
else { settingOverrideFilenameFinal = m_ConfigManager->expand(settingOverrideFilename); }
|
||||
|
||||
// message
|
||||
visitorCtx.getLogManager() << LogLevel_Trace << "Trying to override [" << box.getName() << "] box settings with file [" <<
|
||||
settingOverrideFilename << " which expands to " << settingOverrideFilenameFinal << "] !\n";
|
||||
|
||||
// creates XML reader
|
||||
XML::IReader* reader = createReader(*this);
|
||||
|
||||
// adds new box settings
|
||||
m_Box = &box;
|
||||
m_SettingIdx = 0;
|
||||
m_IsParsingSettingValue = false;
|
||||
m_IsParsingSettingOverride = false;
|
||||
|
||||
auto cleanup = [&]()
|
||||
{
|
||||
// cleans up internal state
|
||||
m_Box = nullptr;
|
||||
m_SettingIdx = 0;
|
||||
m_IsParsingSettingValue = false;
|
||||
m_IsParsingSettingOverride = false;
|
||||
|
||||
// releases XML reader
|
||||
reader->release();
|
||||
reader = nullptr;
|
||||
};
|
||||
|
||||
// 1. Open settings file (binary because read would conflict with tellg for text files)
|
||||
// 2. Loop until end of file, reading it
|
||||
// and sending what is read to the XML parser
|
||||
// 3. Close the settings file
|
||||
std::ifstream file;
|
||||
FS::Files::openIFStream(file, settingOverrideFilenameFinal.toASCIIString(), std::ios::binary);
|
||||
if (file.is_open())
|
||||
{
|
||||
char buffer[1024];
|
||||
bool statusOk = true;
|
||||
file.seekg(0, std::ios::end);
|
||||
std::streamoff fileLen = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
while (fileLen && statusOk)
|
||||
{
|
||||
// File length is always positive so this is safe
|
||||
const std::streamoff bufferLen = (unsigned(fileLen) > sizeof(buffer) ? sizeof(buffer) : fileLen);
|
||||
file.read(buffer, bufferLen);
|
||||
fileLen -= bufferLen;
|
||||
statusOk = reader->processData(buffer, size_t(bufferLen));
|
||||
}
|
||||
file.close();
|
||||
|
||||
// message
|
||||
if (m_SettingIdx == box.getSettingCount())
|
||||
{
|
||||
visitorCtx.getLogManager() << LogLevel_Trace << "Overrode " << m_SettingIdx << " setting(s) with this configuration file...\n";
|
||||
|
||||
for (size_t i = 0; i < m_SettingIdx; ++i)
|
||||
{
|
||||
CString settingName = "";
|
||||
CString rawSettingvalue = "";
|
||||
|
||||
box.getSettingName(i, settingName);
|
||||
box.getSettingValue(i, rawSettingvalue);
|
||||
CString value = rawSettingvalue;
|
||||
value = m_ConfigManager->expand(value);
|
||||
CIdentifier settingType;
|
||||
box.getSettingType(i, settingType);
|
||||
if (!checkSettingValue(value, settingType, visitorCtx.getTypeManager()))
|
||||
{
|
||||
const auto settingTypeName = visitorCtx.getTypeManager().getTypeName(settingType);
|
||||
cleanup();
|
||||
OV_ERROR("<" << box.getName() << "> The following value: [" << rawSettingvalue << "] expanded as [" << value
|
||||
<< "] given as setting is not a valid [" << settingTypeName << "] value.",
|
||||
ErrorType::BadArgument, false, m_ObjectVisitorCtx->getErrorManager(), m_ObjectVisitorCtx->getLogManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanup();
|
||||
OV_ERROR(
|
||||
"Overrode " << m_SettingIdx << " setting(s) with configuration file [" << settingOverrideFilenameFinal <<
|
||||
"]. That does not match the box setting count " << box.getSettingCount(),
|
||||
ErrorType::OutOfBound, false, m_ObjectVisitorCtx->getErrorManager(), m_ObjectVisitorCtx->getLogManager());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (box.hasAttribute(OV_AttributeId_Box_Disabled))
|
||||
{
|
||||
// if the box is disabled do not stop the scenario execution when configuration fails
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanup();
|
||||
OV_ERROR(
|
||||
"Could not override [" << box.getName() << "] settings because configuration file [" << settingOverrideFilenameFinal <<
|
||||
"] could not be opened",
|
||||
ErrorType::ResourceNotFound, false, m_ObjectVisitorCtx->getErrorManager(), m_ObjectVisitorCtx->getLogManager());
|
||||
}
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxSettingModifierVisitor::processEnd(IObjectVisitorContext& visitorCtx, IBox& /*box*/)
|
||||
{
|
||||
m_ObjectVisitorCtx = &visitorCtx;
|
||||
return true;
|
||||
}
|
||||
|
||||
} //namespace Kernel
|
||||
} //namespace OpenViBE
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkCSimulatedBox.h"
|
||||
#include "ovkCPlayer.h"
|
||||
|
||||
#include <openvibe/ovIObjectVisitor.h>
|
||||
#include <openvibe/kernel/ovIObjectVisitorContext.h>
|
||||
|
||||
#include <xml/IReader.h>
|
||||
|
||||
#define OVD_AttributeId_SettingOverrideFilename OpenViBE::CIdentifier(0x8D21FF41, 0xDF6AFE7E)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CBoxSettingModifierVisitor final : public IObjectVisitor, public XML::IReaderCallback
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CBoxSettingModifierVisitor(IConfigurationManager* pConfigurationManager = nullptr)
|
||||
: IObjectVisitor(), m_ConfigManager(pConfigurationManager) {}
|
||||
|
||||
void openChild(const char* name, const char** sAttributeName, const char** sAttributeValue, const size_t nAttribute) override;
|
||||
void processChildData(const char* data) override;
|
||||
void closeChild() override;
|
||||
bool processBegin(IObjectVisitorContext& visitorCtx, IBox& box) override;
|
||||
bool processEnd(IObjectVisitorContext& visitorCtx, IBox& box) override;
|
||||
|
||||
IObjectVisitorContext* m_ObjectVisitorCtx = nullptr;
|
||||
IBox* m_Box = nullptr;
|
||||
size_t m_SettingIdx = 0;
|
||||
bool m_IsParsingSettingValue = false;
|
||||
bool m_IsParsingSettingOverride = false;
|
||||
IConfigurationManager* m_ConfigManager = nullptr;
|
||||
|
||||
_IsDerivedFromClass_Final_(IObjectVisitor, CIdentifier::undefined())
|
||||
};
|
||||
} //namespace Kernel
|
||||
} //namespace OpenViBE
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "ovkCBuffer.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CBuffer::CBuffer(const CBuffer& buffer)
|
||||
{
|
||||
this->CMemoryBuffer::setSize(buffer.getSize(), true);
|
||||
memcpy(this->CMemoryBuffer::getDirectPointer(), buffer.getDirectPointer(), buffer.getSize());
|
||||
}
|
||||
|
||||
CBuffer& CBuffer::operator=(const CBuffer& buffer)
|
||||
{
|
||||
this->CMemoryBuffer::setSize(buffer.getSize(), true);
|
||||
memcpy(this->CMemoryBuffer::getDirectPointer(), buffer.getDirectPointer(), buffer.getSize());
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CBuffer final : public CMemoryBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
CBuffer() { }
|
||||
explicit CBuffer(const CBuffer& buffer);
|
||||
|
||||
CBuffer& operator=(const CBuffer& buffer);
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,356 @@
|
||||
#include "ovkCPlayer.h"
|
||||
#include "ovkCSimulatedBox.h"
|
||||
#include "ovkCScheduler.h"
|
||||
|
||||
#include "../configuration/ovkCConfigurationManager.h"
|
||||
#include "../scenario/ovkCScenarioManager.h"
|
||||
#include "../scenario/ovkCScenarioSettingKeywordParserCallback.h"
|
||||
|
||||
#include <system/ovCTime.h>
|
||||
|
||||
#include <xml/IReader.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
const uint64_t SCHEDULER_DEFAULT_FREQUENCY = 128;
|
||||
const uint64_t SCHEDULER_MAXIMUM_LOOPS_DURATION = (100LL << 22); /* 100/1024 seconds, approx 100ms */
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
CPlayer::CPlayer(const IKernelContext& ctx)
|
||||
: TKernelObject<IPlayer>(ctx), m_kernelCtxBridge(ctx), m_scheduler(m_kernelCtxBridge, *this)
|
||||
{
|
||||
uint64_t schedulerFrequency = this->TKernelObject<IPlayer>::getConfigurationManager().expandAsUInteger("${Kernel_PlayerFrequency}");
|
||||
if (schedulerFrequency == 0)
|
||||
{
|
||||
OV_WARNING_K(std::string("Invalid frequency configuration Kernel_PlayerFrequency = ")
|
||||
+ this->TKernelObject<IPlayer>::getConfigurationManager().expand("${Kernel_PlayerFrequency}").toASCIIString() + " restored to default "
|
||||
+ std::to_string(SCHEDULER_DEFAULT_FREQUENCY));
|
||||
schedulerFrequency = SCHEDULER_DEFAULT_FREQUENCY;
|
||||
}
|
||||
else { TKernelObject<IPlayer>::getLogManager() << LogLevel_Trace << "Player frequency set to " << schedulerFrequency << "\n"; }
|
||||
m_scheduler.setFrequency(schedulerFrequency);
|
||||
}
|
||||
|
||||
CPlayer::~CPlayer()
|
||||
{
|
||||
if (this->isHoldingResources()) { this->uninitialize(); }
|
||||
|
||||
delete m_runtimeConfigManager;
|
||||
delete m_runtimeScenarioManager;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CPlayer::setScenario(const CIdentifier& scenarioID, const CNameValuePairList* localConfigurationTokens)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(!this->isHoldingResources(), "Trying to configure a player with non-empty resources", Kernel::ErrorType::BadCall);
|
||||
|
||||
this->getLogManager() << LogLevel_Debug << "Player setScenario\n";
|
||||
|
||||
// Create a fresh runtime configuration manager which will handle scenario-specific
|
||||
// configuration, such as the scenario settings and local settings (workspace)
|
||||
|
||||
delete m_runtimeConfigManager;
|
||||
m_runtimeConfigManager = new CConfigurationManager(this->getKernelContext(), &this->getKernelContext().getConfigurationManager());
|
||||
m_runtimeConfigManager->addConfigurationFromFile(this->getKernelContext().getConfigurationManager().expand("${Kernel_DelayedConfiguration}"));
|
||||
IScenario& originalScenario = this->getScenarioManager().getScenario(scenarioID);
|
||||
|
||||
delete m_runtimeScenarioManager;
|
||||
m_runtimeScenarioManager = new CScenarioManager(this->getKernelContext());
|
||||
m_runtimeScenarioManager->cloneScenarioImportersAndExporters(this->getKernelContext().getScenarioManager());
|
||||
|
||||
OV_ERROR_UNLESS_KRF(m_runtimeScenarioManager->createScenario(m_runtimeScenarioID),
|
||||
"Fail to create a scenario duplicate for the current runtime session", Kernel::ErrorType::BadResourceCreation);
|
||||
|
||||
IScenario& runtimeScenario = m_runtimeScenarioManager->getScenario(m_runtimeScenarioID);
|
||||
runtimeScenario.merge(originalScenario, nullptr, true, true);
|
||||
|
||||
if (runtimeScenario.hasAttribute(OV_AttributeId_ScenarioFilename))
|
||||
{
|
||||
const std::string filename = runtimeScenario.getAttributeValue(OV_AttributeId_ScenarioFilename).toASCIIString();
|
||||
std::string directoryName = ".";
|
||||
m_runtimeConfigManager->createConfigurationToken("Player_ScenarioFilename", filename.c_str());
|
||||
|
||||
const size_t iDir = filename.rfind('/');
|
||||
if (iDir != std::string::npos) { directoryName = filename.substr(0, iDir); }
|
||||
m_runtimeConfigManager->createConfigurationToken("Player_ScenarioDirectory", directoryName.c_str());
|
||||
m_runtimeConfigManager->createConfigurationToken("__volatile_ScenarioDir", directoryName.c_str());
|
||||
const std::string workspaceConfigurationFile = directoryName + "/" + std::string("openvibe-workspace.conf");
|
||||
this->getLogManager() << LogLevel_Trace << "Player adds workspace configuration file [" << workspaceConfigurationFile <<
|
||||
"] to runtime configuration manager\n";
|
||||
m_runtimeConfigManager->addConfigurationFromFile(CString(workspaceConfigurationFile.c_str()));
|
||||
std::string scenarioConfigurationFile = directoryName + "/" + std::string("scenario.conf");
|
||||
this->getLogManager() << LogLevel_Trace << "Player adds scenario configuration file [" << scenarioConfigurationFile <<
|
||||
"] to runtime configuration manager\n";
|
||||
m_runtimeConfigManager->addConfigurationFromFile(CString(scenarioConfigurationFile.c_str()));
|
||||
|
||||
const size_t ext = filename.rfind('.');
|
||||
if (ext != std::string::npos)
|
||||
{
|
||||
scenarioConfigurationFile = filename.substr(0, ext) + std::string(".conf");
|
||||
this->getLogManager() << LogLevel_Trace << "Player adds scenario configuration file [" << scenarioConfigurationFile <<
|
||||
"] to runtime configuration manager\n";
|
||||
m_runtimeConfigManager->addConfigurationFromFile(CString(scenarioConfigurationFile.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// Sets configuration tokens for this player
|
||||
// Once every token file, applies the configuration tokens coming from an external application defining its own scenario specific tokens
|
||||
if (localConfigurationTokens != nullptr)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Player setScenario: add local configuration token from map.\n";
|
||||
for (size_t i = 0; i < localConfigurationTokens->getSize(); ++i)
|
||||
{
|
||||
CString name;
|
||||
CString value;
|
||||
if (localConfigurationTokens->getValue(i, name, value))
|
||||
{
|
||||
this->getLogManager() << LogLevel_Debug << "Player setScenario: add local configuration token: [" << name << "] = [" << value << "].\n";
|
||||
CIdentifier tokenID = m_runtimeConfigManager->lookUpConfigurationTokenIdentifier(name);
|
||||
if (tokenID == CIdentifier::undefined()) { m_runtimeConfigManager->createConfigurationToken(name, value); }
|
||||
else { m_runtimeConfigManager->setConfigurationTokenValue(tokenID, value); }
|
||||
}
|
||||
// This should not happen
|
||||
else
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Player setScenario: Could not acces to value of localConfigurationTokens at index " << i <<
|
||||
".\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_KRF(runtimeScenario.checkSettings(m_runtimeConfigManager),
|
||||
"Checking settings failed for scenario duplicate instantiated for the current runtime session", Kernel::ErrorType::BadArgument);
|
||||
|
||||
return m_scheduler.setScenario(m_runtimeScenarioID);
|
||||
}
|
||||
|
||||
IConfigurationManager& CPlayer::getRuntimeConfigurationManager() const { return *m_runtimeConfigManager; }
|
||||
IScenarioManager& CPlayer::getRuntimeScenarioManager() const { return *m_runtimeScenarioManager; }
|
||||
CIdentifier CPlayer::getRuntimeScenarioIdentifier() const { return m_runtimeScenarioID; }
|
||||
|
||||
EPlayerReturnCodes CPlayer::initialize()
|
||||
{
|
||||
OV_ERROR_UNLESS_K(!this->isHoldingResources(), "Trying to configure a player with non-empty resources", Kernel::ErrorType::BadCall,
|
||||
EPlayerReturnCodes::Failed);
|
||||
|
||||
this->getLogManager() << LogLevel_Trace << "Player initialized.\n";
|
||||
|
||||
m_fastForwardMaximumFactor = 0;
|
||||
// At this point we've inserted the bridge as a stand-in for Kernel context to the local CConfigurationManager, but the manager in the bridge is still the
|
||||
// 'global' one. Now lets change the config manager in the bridge to point to the local manager in order to load configurations into the local manager.
|
||||
m_kernelCtxBridge.setConfigurationManager(m_runtimeConfigManager);
|
||||
|
||||
const ESchedulerInitialization code = m_scheduler.initialize();
|
||||
|
||||
if (code == ESchedulerInitialization::Failed) { OV_ERROR_K("Failed to initialize player", Kernel::ErrorType::Internal, EPlayerReturnCodes::Failed); }
|
||||
if (code == ESchedulerInitialization::BoxInitializationFailed)
|
||||
{
|
||||
OV_ERROR_K("Failed to initialize player", Kernel::ErrorType::Internal, EPlayerReturnCodes::BoxInitializationFailed);
|
||||
}
|
||||
|
||||
m_benchmarkChrono.reset(size_t(m_scheduler.getFrequency()));
|
||||
|
||||
m_currentTimeToReach = 0;
|
||||
m_lateness = 0;
|
||||
m_innerLateness = 0;
|
||||
|
||||
m_status = EPlayerStatus::Stop;
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
bool CPlayer::uninitialize()
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Player uninitialize\n";
|
||||
|
||||
m_scheduler.uninitialize();
|
||||
m_kernelCtxBridge.setConfigurationManager(nullptr);
|
||||
|
||||
m_scenarioConfigFile = "";
|
||||
m_workspaceConfigFile = "";
|
||||
if (m_runtimeConfigManager != nullptr)
|
||||
{
|
||||
delete m_runtimeConfigManager;
|
||||
m_runtimeConfigManager = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlayer::stop()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized player", Kernel::ErrorType::BadCall);
|
||||
this->getLogManager() << LogLevel_Trace << "Player stop\n";
|
||||
m_status = EPlayerStatus::Stop;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlayer::pause()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized player", Kernel::ErrorType::BadCall);
|
||||
this->getLogManager() << LogLevel_Trace << "Player pause\n";
|
||||
m_status = EPlayerStatus::Pause;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlayer::step()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized player", Kernel::ErrorType::BadCall);
|
||||
this->getLogManager() << LogLevel_Trace << "Player step\n";
|
||||
m_status = EPlayerStatus::Step;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlayer::play()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized player", Kernel::ErrorType::BadCall);
|
||||
this->getLogManager() << LogLevel_Trace << "Player play\n";
|
||||
m_status = EPlayerStatus::Play;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlayer::forward()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized player", Kernel::ErrorType::BadCall);
|
||||
this->getLogManager() << LogLevel_Trace << "Player forward\n";
|
||||
m_status = EPlayerStatus::Forward;
|
||||
return true;
|
||||
}
|
||||
|
||||
EPlayerStatus CPlayer::getStatus() const { return m_status; }
|
||||
|
||||
bool CPlayer::setFastForwardMaximumFactor(const double fastForwardFactor)
|
||||
{
|
||||
m_fastForwardMaximumFactor = (fastForwardFactor < 0 ? 0 : fastForwardFactor);
|
||||
return true;
|
||||
}
|
||||
|
||||
double CPlayer::getFastForwardMaximumFactor() const { return m_fastForwardMaximumFactor; }
|
||||
double CPlayer::getCPUUsage() const { return m_scheduler.getCPUUsage(); }
|
||||
bool CPlayer::isHoldingResources() const { return m_scheduler.isHoldingResources(); }
|
||||
|
||||
bool CPlayer::loop(const uint64_t elapsedTime, const uint64_t maximumTimeToReach)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized player", Kernel::ErrorType::BadCall);
|
||||
|
||||
if (m_status == EPlayerStatus::Stop) { return true; }
|
||||
|
||||
bool hasTimeToReach = false;
|
||||
switch (m_status)
|
||||
{
|
||||
// Calls a single controller loop and goes back to pause state
|
||||
case EPlayerStatus::Step:
|
||||
m_currentTimeToReach += CTime(m_scheduler.getFrequency(), 1LL).time();
|
||||
hasTimeToReach = true;
|
||||
m_status = EPlayerStatus::Pause;
|
||||
break;
|
||||
|
||||
// Calls multiple controller loops
|
||||
case EPlayerStatus::Forward:
|
||||
// We can't know what m_currentTimeToReach should be in advance
|
||||
// We will try to do as many scheduler loops as possible until
|
||||
// SCHEDULER_MAXIMUM_LOOPS_DURATION seconds elapsed
|
||||
if (m_fastForwardMaximumFactor != 0)
|
||||
{
|
||||
m_currentTimeToReach += uint64_t(m_fastForwardMaximumFactor * elapsedTime);
|
||||
hasTimeToReach = true;
|
||||
}
|
||||
break;
|
||||
|
||||
// Simply updates time according to delta time
|
||||
case EPlayerStatus::Play:
|
||||
m_currentTimeToReach += elapsedTime;
|
||||
hasTimeToReach = true;
|
||||
break;
|
||||
|
||||
default: return true;
|
||||
}
|
||||
|
||||
#if defined CPlayer_Debug_Time
|
||||
::printf("---\n");
|
||||
::printf("Factor : %lf\n", m_fastForwardMaximumFactor);
|
||||
::printf("Current time : %llx\n", m_scheduler.getCurrentTime());
|
||||
::printf("Time to reach : %llx\n", m_currentTimeToReach);
|
||||
#endif // CPlayer_Debug_Time
|
||||
|
||||
const uint64_t schedulerStepDuration = m_scheduler.getStepDuration();
|
||||
const uint64_t tStart = System::Time::zgetTime();
|
||||
bool finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
const uint64_t nextSchedulerTime = m_scheduler.getCurrentTime() + schedulerStepDuration;
|
||||
|
||||
#if defined CPlayer_Debug_Time
|
||||
::printf(" Next time : %llx\n", nextSchedulerTime);
|
||||
#endif // CPlayer_Debug_Time
|
||||
if (m_status == EPlayerStatus::Stop) { finished = true; }
|
||||
|
||||
if ((hasTimeToReach && (nextSchedulerTime > m_currentTimeToReach)) || (
|
||||
(m_status == EPlayerStatus::Forward || hasTimeToReach) && (m_scheduler.getCurrentTime() >= maximumTimeToReach)))
|
||||
{
|
||||
finished = true;
|
||||
#if defined CPlayer_Debug_Time
|
||||
::printf("Breaks because would get over time to reach\n");
|
||||
#endif // CPlayer_Debug_Time
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasTimeToReach) { m_innerLateness = (m_currentTimeToReach > nextSchedulerTime ? m_currentTimeToReach - nextSchedulerTime : 0); }
|
||||
else { m_innerLateness = 0; }
|
||||
|
||||
if (!m_scheduler.loop())
|
||||
{
|
||||
m_status = EPlayerStatus::Stop;
|
||||
this->getLogManager() << LogLevel_Error << "Scheduler loop failed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined CPlayer_Debug_Time
|
||||
::printf("Iterates (%f / %f - %s)\n", (m_scheduler.getCurrentTime()>>22)/1024., (maximumTimeToReach>>22)/1024., (m_status==EPlayerStatus::Forward?"true":"false"));
|
||||
#endif // CPlayer_Debug_Time
|
||||
}
|
||||
if (System::Time::zgetTime() > tStart + SCHEDULER_MAXIMUM_LOOPS_DURATION)
|
||||
{
|
||||
finished = true;
|
||||
#if defined CPlayer_Debug_Time
|
||||
::printf("Breaks because of loop time out\n");
|
||||
#endif // CPlayer_Debug_Time
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_status == EPlayerStatus::Forward && m_currentTimeToReach > m_scheduler.getCurrentTime() + schedulerStepDuration) || !hasTimeToReach)
|
||||
{
|
||||
m_currentTimeToReach = m_scheduler.getCurrentTime();
|
||||
}
|
||||
|
||||
uint64_t lateness;
|
||||
if (m_currentTimeToReach > m_scheduler.getCurrentTime()) { lateness = m_currentTimeToReach - m_scheduler.getCurrentTime(); }
|
||||
else { lateness = 0; }
|
||||
|
||||
#if defined CPlayer_Debug_Time
|
||||
::printf("Done -- New time to reach : %llx\n", m_currentTimeToReach);
|
||||
#endif // CPlayer_Debug_Time
|
||||
|
||||
const uint64_t latenessSec = lateness >> 32;
|
||||
const uint64_t prevlatenessSec = m_lateness >> 32;
|
||||
std::stringstream ss;
|
||||
ss << "<" << LogColor_PushStateBit << LogColor_ForegroundBlue << "Player" << LogColor_PopStateBit << "::" << LogColor_PushStateBit
|
||||
<< LogColor_ForegroundBlue << "can not reach realtime" << LogColor_PopStateBit << "> " << latenessSec << " second(s) late...\n";
|
||||
OV_WARNING_UNLESS_K(latenessSec == prevlatenessSec, ss.str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t CPlayer::getCurrentSimulatedTime() const { return m_scheduler.getCurrentTime(); }
|
||||
uint64_t CPlayer::getCurrentSimulatedLateness() const { return m_innerLateness; }
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
#include "ovkCScheduler.h"
|
||||
|
||||
#include "../ovkCKernelContext.h"
|
||||
|
||||
#include <system/ovCChrono.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScenarioSettingKeywordParserCallback;
|
||||
|
||||
class CPlayer final : public TKernelObject<IPlayer>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPlayer(const IKernelContext& ctx);
|
||||
~CPlayer() override;
|
||||
bool setScenario(const CIdentifier& scenarioID, const CNameValuePairList* localConfigurationTokens) override;
|
||||
IConfigurationManager& getRuntimeConfigurationManager() const override;
|
||||
IScenarioManager& getRuntimeScenarioManager() const override;
|
||||
CIdentifier getRuntimeScenarioIdentifier() const override;
|
||||
|
||||
|
||||
bool isHoldingResources() const;
|
||||
EPlayerReturnCodes initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool stop() override;
|
||||
bool pause() override;
|
||||
bool step() override;
|
||||
bool play() override;
|
||||
bool forward() override;
|
||||
EPlayerStatus getStatus() const override;
|
||||
bool setFastForwardMaximumFactor(double fastForwardFactor) override;
|
||||
double getFastForwardMaximumFactor() const override;
|
||||
double getCPUUsage() const override;
|
||||
bool loop(uint64_t elapsedTime, uint64_t maximumTimeToReach) override;
|
||||
uint64_t getCurrentSimulatedTime() const override;
|
||||
uint64_t getCurrentSimulatedLateness() const;
|
||||
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPlayer>, OVK_ClassId_Kernel_Player_Player)
|
||||
|
||||
protected:
|
||||
|
||||
CKernelContextBridge m_kernelCtxBridge;
|
||||
IConfigurationManager* m_runtimeConfigManager = nullptr;
|
||||
IScenarioManager* m_runtimeScenarioManager = nullptr;
|
||||
CScenarioSettingKeywordParserCallback* m_scenarioSettingKeywordParserCB = nullptr;
|
||||
|
||||
CScheduler m_scheduler;
|
||||
|
||||
uint64_t m_currentTimeToReach = 0;
|
||||
uint64_t m_lateness = 0;
|
||||
uint64_t m_innerLateness = 0;
|
||||
EPlayerStatus m_status = EPlayerStatus::Stop;
|
||||
bool m_isInitializing = false;
|
||||
double m_fastForwardMaximumFactor = 0;
|
||||
|
||||
std::string m_scenarioConfigFile;
|
||||
std::string m_workspaceConfigFile;
|
||||
|
||||
// Stores the identifier of the scenario that is being played
|
||||
CIdentifier m_scenarioID = CIdentifier::undefined();
|
||||
|
||||
private:
|
||||
CIdentifier m_runtimeScenarioID = CIdentifier::undefined();
|
||||
|
||||
System::CChrono m_benchmarkChrono;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "ovkCPlayerContext.h"
|
||||
#include "ovkCSimulatedBox.h"
|
||||
#include "ovkCScheduler.h"
|
||||
#include "ovkCPlayer.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CPlayerContext::CPlayerContext(const IKernelContext& ctx, CSimulatedBox* pSimulatedBox)
|
||||
: TKernelObject<IPlayerContext>(ctx), m_simulatedBox(*pSimulatedBox), m_pluginManager(ctx.getPluginManager()),
|
||||
m_algorithmManager(ctx.getAlgorithmManager()), m_configManager(ctx.getConfigurationManager()),
|
||||
m_logManager(ctx.getLogManager()), m_errorManager(ctx.getErrorManager()), m_scenarioManager(ctx.getScenarioManager()),
|
||||
m_typeManager(ctx.getTypeManager()), m_boxLogManager(*this, m_logManager, m_simulatedBox) {}
|
||||
|
||||
uint64_t CPlayerContext::getCurrentTime() const { return m_simulatedBox.getScheduler().getCurrentTime(); }
|
||||
uint64_t CPlayerContext::getCurrentLateness() const { return m_simulatedBox.getScheduler().getCurrentLateness(); }
|
||||
double CPlayerContext::getCurrentCPUUsage() const { return m_simulatedBox.getScheduler().getCPUUsage(); }
|
||||
double CPlayerContext::getCurrentFastForwardMaximumFactor() const { return m_simulatedBox.getScheduler().getFastForwardMaximumFactor(); }
|
||||
|
||||
bool CPlayerContext::stop() { return m_simulatedBox.getScheduler().getPlayer().stop(); }
|
||||
bool CPlayerContext::pause() { return m_simulatedBox.getScheduler().getPlayer().pause(); }
|
||||
bool CPlayerContext::play() { return m_simulatedBox.getScheduler().getPlayer().play(); }
|
||||
bool CPlayerContext::forward() { return m_simulatedBox.getScheduler().getPlayer().forward(); }
|
||||
|
||||
EPlayerStatus CPlayerContext::getStatus() const { return m_simulatedBox.getScheduler().getPlayer().getStatus(); }
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovkCBoxAlgorithmLogManager.h"
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CSimulatedBox;
|
||||
|
||||
class CPlayerContext final : public TKernelObject<IPlayerContext>
|
||||
{
|
||||
public:
|
||||
|
||||
CPlayerContext(const IKernelContext& ctx, CSimulatedBox* pSimulatedBox);
|
||||
~CPlayerContext() override { }
|
||||
|
||||
uint64_t getCurrentTime() const override;
|
||||
uint64_t getCurrentLateness() const override;
|
||||
double getCurrentCPUUsage() const override;
|
||||
double getCurrentFastForwardMaximumFactor() const override;
|
||||
|
||||
bool stop() override;
|
||||
bool pause() override;
|
||||
bool play() override;
|
||||
bool forward() override;
|
||||
EPlayerStatus getStatus() const override;
|
||||
|
||||
IAlgorithmManager& getAlgorithmManager() const override { return m_algorithmManager; }
|
||||
IConfigurationManager& getConfigurationManager() const override { return m_configManager; }
|
||||
ILogManager& getLogManager() const override { return m_boxLogManager; }
|
||||
IErrorManager& getErrorManager() const override { return m_errorManager; }
|
||||
IScenarioManager& getScenarioManager() const override { return m_scenarioManager; }
|
||||
ITypeManager& getTypeManager() const override { return m_typeManager; }
|
||||
bool canCreatePluginObject(const CIdentifier& pluginID) const override { return m_pluginManager.canCreatePluginObject(pluginID); }
|
||||
Plugins::IPluginObject* createPluginObject(const CIdentifier& pluginID) const override { return m_pluginManager.createPluginObject(pluginID); }
|
||||
bool releasePluginObject(Plugins::IPluginObject* pluginObject) const override { return m_pluginManager.releasePluginObject(pluginObject); }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPlayerContext>, OVK_ClassId_Kernel_Player_PlayerContext)
|
||||
|
||||
private:
|
||||
|
||||
CSimulatedBox& m_simulatedBox;
|
||||
IPluginManager& m_pluginManager;
|
||||
IAlgorithmManager& m_algorithmManager;
|
||||
IConfigurationManager& m_configManager;
|
||||
ILogManager& m_logManager;
|
||||
IErrorManager& m_errorManager;
|
||||
IScenarioManager& m_scenarioManager;
|
||||
ITypeManager& m_typeManager;
|
||||
mutable CBoxAlgorithmLogManager m_boxLogManager;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "ovkCPlayerManager.h"
|
||||
#include "ovkCPlayer.h"
|
||||
|
||||
#include <system/ovCMath.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
bool CPlayerManager::createPlayer(CIdentifier& playerID)
|
||||
{
|
||||
playerID = getUnusedIdentifier();
|
||||
m_players[playerID] = new CPlayer(getKernelContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlayerManager::releasePlayer(const CIdentifier& playerID)
|
||||
{
|
||||
auto it = m_players.find(playerID);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(it != m_players.end(), "Player release failed, identifier :" << playerID.str(), Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
delete it->second;
|
||||
m_players.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
IPlayer& CPlayerManager::getPlayer(const CIdentifier& playerID)
|
||||
{
|
||||
const auto it = m_players.find(playerID);
|
||||
|
||||
// use fatal here because the signature does not allow
|
||||
// proper checking
|
||||
OV_FATAL_UNLESS_K(it != m_players.end(), "Trying to retrieve non existing player with id " << playerID.str(), Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
// use a fatal here because failing to meet this invariant
|
||||
// means there is a bug in the manager implementation
|
||||
OV_FATAL_UNLESS_K(it->second, "Null player found for id " << playerID.str(), Kernel::ErrorType::BadValue);
|
||||
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
CIdentifier CPlayerManager::getUnusedIdentifier() const
|
||||
{
|
||||
uint64_t id = CIdentifier::random().id();
|
||||
CIdentifier res;
|
||||
std::map<CIdentifier, CPlayer*>::const_iterator i;
|
||||
do
|
||||
{
|
||||
id++;
|
||||
res = CIdentifier(id);
|
||||
i = m_players.find(res);
|
||||
} while (i != m_players.end() || res == CIdentifier::undefined());
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CPlayer;
|
||||
|
||||
class CPlayerManager final : public TKernelObject<IPlayerManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPlayerManager(const IKernelContext& ctx) : TKernelObject<IPlayerManager>(ctx) {}
|
||||
bool createPlayer(CIdentifier& playerID) override;
|
||||
bool releasePlayer(const CIdentifier& playerID) override;
|
||||
IPlayer& getPlayer(const CIdentifier& playerID) override;
|
||||
CIdentifier getNextPlayerIdentifier(const CIdentifier& previousID) const override { return getNextIdentifier<CPlayer*>(m_players, previousID); }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPlayerManager>, OVK_ClassId_Kernel_Player_PlayerManager)
|
||||
|
||||
protected:
|
||||
|
||||
CIdentifier getUnusedIdentifier() const;
|
||||
|
||||
std::map<CIdentifier, CPlayer*> m_players;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+638
@@ -0,0 +1,638 @@
|
||||
#include <openvibe/ovExceptionHandler.h>
|
||||
|
||||
#include "ovkCScheduler.h"
|
||||
#include "ovkCSimulatedBox.h"
|
||||
#include "ovkCPlayer.h"
|
||||
#include "../scenario/ovkCScenarioSettingKeywordParserCallback.h"
|
||||
#include "ovkCBoxSettingModifierVisitor.h"
|
||||
|
||||
#include <fs/Files.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <set>
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#define stricmp _stricmp
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
#include <strings.h>
|
||||
#define stricmp strcasecmp
|
||||
#else
|
||||
// TODO
|
||||
#endif
|
||||
|
||||
#include <ovp_global_defines.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
#define OVTK_Algorithm_ScenarioImporter_OutputParameterId_Scenario CIdentifier(0x29574C87, 0x7BA77780)
|
||||
#define OVTK_Algorithm_ScenarioImporter_InputParameterId_MemoryBuffer CIdentifier(0x600463A3, 0x474B7F66)
|
||||
|
||||
#define OV_AttributeId_Box_Disabled CIdentifier(0x341D3912, 0x1478DE86)
|
||||
|
||||
CScheduler::CScheduler(const IKernelContext& ctx, CPlayer& player)
|
||||
: TKernelObject<IKernelObject>(ctx), m_rPlayer(player), m_scenarioID(CIdentifier::undefined()) {}
|
||||
|
||||
CScheduler::~CScheduler() { this->uninitialize(); }
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CScheduler::setScenario(const CIdentifier& scenarioID)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Scheduler setScenario\n";
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!this->isHoldingResources(), "Trying to configure a scheduler with non-empty resources", Kernel::ErrorType::BadCall);
|
||||
|
||||
m_scenarioID = scenarioID;
|
||||
|
||||
// We need to flatten the scenario here as the application using the scheduler needs time
|
||||
// between the moment the visualisation tree is complete and the moment when boxes are initialized.
|
||||
// The application needs to initialize necessary windows for the boxes to draw into.
|
||||
m_scenario = &m_rPlayer.getRuntimeScenarioManager().getScenario(m_scenarioID);
|
||||
|
||||
if (!this->flattenScenario())
|
||||
{
|
||||
// error handling is performed within flattenScenario
|
||||
return false;
|
||||
}
|
||||
|
||||
m_scenario = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScheduler::setFrequency(const uint64_t frequency)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Scheduler setFrequency\n";
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!this->isHoldingResources(), "Trying to configure a scheduler with non-empty resources", Kernel::ErrorType::BadCall);
|
||||
|
||||
m_frequency = frequency;
|
||||
m_stepDuration = (1LL << 32) / frequency;
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CScheduler::isHoldingResources() const { return !m_simulatedBoxes.empty(); }
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CScheduler::flattenScenario()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_scenario->applyLocalSettings(), "Failed to flatten scenario: applying local settings failed", Kernel::ErrorType::Internal);
|
||||
|
||||
// We are going to find all metaboxes in the scenario and then push their contents to this one
|
||||
// As the scenario itself can contain more metaboxes, we are going to repeat this process
|
||||
// util there are no unhandled metaboxes left
|
||||
bool hasFinishedHandlingMetaboxes = false;
|
||||
|
||||
while (!hasFinishedHandlingMetaboxes)
|
||||
{
|
||||
// First find all the metaboxes in the scenario
|
||||
std::vector<CIdentifier> scenarioMetaboxes;
|
||||
|
||||
{
|
||||
CIdentifier* listID = nullptr;
|
||||
size_t nbElems = 0;
|
||||
m_scenario->getBoxIdentifierList(&listID, &nbElems);
|
||||
for (size_t i = 0; i < nbElems; ++i)
|
||||
{
|
||||
const CIdentifier boxID = listID[i];
|
||||
const IBox* box = m_scenario->getBoxDetails(boxID);
|
||||
|
||||
if (box->getAlgorithmClassIdentifier() == OVP_ClassId_BoxAlgorithm_Metabox)
|
||||
{
|
||||
if (box->hasAttribute(OV_AttributeId_Box_Disabled)) // We only process this box if it is not disabled
|
||||
{
|
||||
m_scenario->removeBox(boxID);
|
||||
}
|
||||
else if (box->hasAttribute(OVP_AttributeId_Metabox_ID)) // We verify that the box actually has a backend scenario
|
||||
{
|
||||
CIdentifier metaboxId;
|
||||
metaboxId.fromString(box->getAttributeValue(OVP_AttributeId_Metabox_ID));
|
||||
CString metaboxScenarioPath(this->getKernelContext().getMetaboxManager().getMetaboxFilePath(metaboxId));
|
||||
|
||||
if (FS::Files::fileExists(metaboxScenarioPath.toASCIIString()))
|
||||
{
|
||||
// If the scenario exists we will handle this metabox
|
||||
scenarioMetaboxes.push_back(boxID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-utilisable metaboxes can be easily removed
|
||||
OV_WARNING_K("The scenario for metabox [" << metaboxId.str() << "] is missing.");
|
||||
m_scenario->removeBox(boxID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OV_WARNING_K("The metabox [" << boxID << "] is missing its identifier field.");
|
||||
m_scenario->removeBox(boxID);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_scenario->releaseIdentifierList(listID);
|
||||
}
|
||||
|
||||
if (scenarioMetaboxes.empty()) { hasFinishedHandlingMetaboxes = true; }
|
||||
|
||||
// Now load each of the found metaboxes, load the scenario that represents it
|
||||
// Assign the settings from the box to the scenario
|
||||
// Calculate new settings for each box inside this scenario (by expanding $var settings)
|
||||
// Merge the scenario into this one
|
||||
// Re-connect all links for the scenario
|
||||
|
||||
for (const auto& boxID : scenarioMetaboxes)
|
||||
{
|
||||
IBox* box = m_scenario->getBoxDetails(boxID);
|
||||
|
||||
// The box has an attribute with the metabox ID and config manager has a path to each metabox scenario
|
||||
CString str = box->getAttributeValue(OVP_AttributeId_Metabox_ID);
|
||||
CIdentifier metaboxId;
|
||||
metaboxId.fromString(str);
|
||||
CString metaboxScenarioPath(this->getKernelContext().getMetaboxManager().getMetaboxFilePath(metaboxId));
|
||||
|
||||
OV_ERROR_UNLESS_KRF(str != CString(""), "Failed to find metabox with id " << str, Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
// We are going to copy the template scenario, flatten it and then copy all
|
||||
// Note that copy constructor for IScenario does not exist
|
||||
CIdentifier metaboxScenarioTemplateID;
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
m_rPlayer.getRuntimeScenarioManager().importScenarioFromFile(metaboxScenarioTemplateID,
|
||||
OV_ScenarioImportContext_SchedulerMetaboxImport, metaboxScenarioPath),
|
||||
"Failed to import the scenario file", Kernel::ErrorType::Internal);
|
||||
|
||||
IScenario& metaboxScenarioInstance = m_rPlayer.getRuntimeScenarioManager().getScenario(metaboxScenarioTemplateID);
|
||||
|
||||
OV_WARNING_UNLESS_K(metaboxScenarioInstance.hasAttribute(OV_AttributeId_Scenario_MetaboxHash),
|
||||
"Box " << box->getName() << " [" << metaboxScenarioPath << "] has no computed hash");
|
||||
|
||||
OV_WARNING_UNLESS_K(
|
||||
box->getAttributeValue(OV_AttributeId_Box_InitialPrototypeHashValue) == metaboxScenarioInstance.getAttributeValue(
|
||||
OV_AttributeId_Scenario_MetaboxHash),
|
||||
"Box " << box->getName() << " [" << str << "] should be updated");
|
||||
|
||||
metaboxScenarioInstance.addAttribute(OV_AttributeId_ScenarioFilename, metaboxScenarioPath);
|
||||
|
||||
// Push down the settings from the box to the scenario
|
||||
for (size_t idx = 0; idx < box->getSettingCount(); ++idx)
|
||||
{
|
||||
CString value;
|
||||
CIdentifier id;
|
||||
|
||||
box->getSettingValue(idx, value);
|
||||
box->getInterfacorIdentifier(Setting, idx, id);
|
||||
|
||||
if (id != CIdentifier::undefined()) { metaboxScenarioInstance.setSettingValue(id, value); }
|
||||
else { metaboxScenarioInstance.setSettingValue(idx, value); }
|
||||
}
|
||||
|
||||
// Create settings with the path to the Metabox,
|
||||
// these settings will be accessible from within the Metabox on runtime
|
||||
std::string metaboxFilename = metaboxScenarioPath.toASCIIString();
|
||||
std::string metaboxDirectoryPath = ".";
|
||||
metaboxScenarioInstance.addSetting("Player_MetaboxScenarioFilename", OV_TypeId_Filename, metaboxScenarioPath);
|
||||
|
||||
const size_t lastSlashPos = metaboxFilename.rfind('/');
|
||||
if (lastSlashPos != std::string::npos) { metaboxDirectoryPath = metaboxFilename.substr(0, lastSlashPos); }
|
||||
|
||||
metaboxScenarioInstance.addSetting("Player_MetaboxScenarioDirectory", OV_TypeId_Foldername, metaboxDirectoryPath.c_str());
|
||||
|
||||
// apply the settings within the loaded scenario
|
||||
metaboxScenarioInstance.applyLocalSettings();
|
||||
|
||||
std::map<CIdentifier, CIdentifier> correspondenceID;
|
||||
class CScenarioMergeCallback : public IScenario::IScenarioMergeCallback
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
CScenarioMergeCallback(std::map<CIdentifier, CIdentifier>& rIdentifierCorrespondence) : m_correspondenceID(rIdentifierCorrespondence) { }
|
||||
|
||||
void process(CIdentifier& originalID, CIdentifier& newId) override { m_correspondenceID[originalID] = newId; }
|
||||
|
||||
private:
|
||||
std::map<CIdentifier, CIdentifier>& m_correspondenceID;
|
||||
};
|
||||
|
||||
CScenarioMergeCallback scenarioMergeCB(correspondenceID);
|
||||
|
||||
// Copy the boxes and the links from the template metabox scenario to this one
|
||||
m_scenario->merge(metaboxScenarioInstance, &scenarioMergeCB, false, false);
|
||||
|
||||
// Now reconnect all the pipes
|
||||
|
||||
// Connect metabox inputs
|
||||
{
|
||||
CIdentifier* listID = nullptr;
|
||||
size_t nbElems = 0;
|
||||
m_scenario->getLinkIdentifierToBoxList(box->getIdentifier(), &listID, &nbElems);
|
||||
for (size_t i = 0; i < nbElems; ++i)
|
||||
{
|
||||
ILink* link = m_scenario->getLinkDetails(listID[i]);
|
||||
// Find out the target inside the metabox scenario
|
||||
CIdentifier dstBoxID;
|
||||
size_t dstBoxInputIdx = 0;
|
||||
CIdentifier metaBoxInputID = link->getTargetBoxInputIdentifier();
|
||||
size_t metaBoxInputIdx = link->getTargetBoxInputIndex();
|
||||
|
||||
if (metaBoxInputID != CIdentifier::undefined()) { metaboxScenarioInstance.getInterfacorIndex(Input, metaBoxInputID, metaBoxInputIdx); }
|
||||
OV_ERROR_UNLESS_KRF(metaBoxInputIdx != size_t(-1), "Failed to find metabox input with identifier " << metaBoxInputID.str(),
|
||||
ErrorType::ResourceNotFound);
|
||||
metaboxScenarioInstance.getScenarioInputLink(metaBoxInputIdx, dstBoxID, dstBoxInputIdx);
|
||||
|
||||
// Now redirect the link to the newly created copy of the box in the scenario
|
||||
CIdentifier dstBoxInputID = CIdentifier::undefined();
|
||||
if (dstBoxID != CIdentifier::undefined())
|
||||
{
|
||||
m_scenario->getBoxDetails(correspondenceID[dstBoxID])->getInterfacorIdentifier(Input, dstBoxInputIdx, dstBoxInputID);
|
||||
link->setTarget(correspondenceID[dstBoxID], dstBoxInputIdx, dstBoxInputID);
|
||||
}
|
||||
}
|
||||
m_scenario->releaseIdentifierList(listID);
|
||||
}
|
||||
|
||||
// Connect metabox outputs
|
||||
{
|
||||
CIdentifier* listID = nullptr;
|
||||
size_t nbElems = 0;
|
||||
m_scenario->getLinkIdentifierFromBoxList(box->getIdentifier(), &listID, &nbElems);
|
||||
for (size_t i = 0; i < nbElems; ++i)
|
||||
{
|
||||
ILink* link = m_scenario->getLinkDetails(listID[i]);
|
||||
// Find out the Source inside the metabox scenario
|
||||
CIdentifier srcBoxID;
|
||||
size_t srcBoxOutputIdx = 0;
|
||||
CIdentifier metaBoxOutputID = link->getSourceBoxOutputIdentifier();
|
||||
size_t metaBoxOutputIdx = link->getSourceBoxOutputIndex();
|
||||
|
||||
if (metaBoxOutputID != CIdentifier::undefined()) { metaboxScenarioInstance.getInterfacorIndex(Output, metaBoxOutputID, metaBoxOutputIdx); }
|
||||
OV_ERROR_UNLESS_KRF(metaBoxOutputIdx != size_t(-1),
|
||||
"Failed to find metabox input with identifier " << metaBoxOutputID.str(), Kernel::ErrorType::ResourceNotFound);
|
||||
metaboxScenarioInstance.getScenarioOutputLink(metaBoxOutputIdx, srcBoxID, srcBoxOutputIdx);
|
||||
|
||||
// Now redirect the link to the newly created copy of the box in the scenario
|
||||
CIdentifier srcBoxOutputID = CIdentifier::undefined();
|
||||
if (srcBoxID != CIdentifier::undefined())
|
||||
{
|
||||
m_scenario->getBoxDetails(correspondenceID[srcBoxID])->getInterfacorIdentifier(Output, srcBoxOutputIdx, srcBoxOutputID);
|
||||
|
||||
link->setSource(correspondenceID[srcBoxID], srcBoxOutputIdx, srcBoxOutputID);
|
||||
}
|
||||
}
|
||||
m_scenario->releaseIdentifierList(listID);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove processed metaboxes from the scenario
|
||||
for (const CIdentifier& metaboxID : scenarioMetaboxes) { m_scenario->removeBox(metaboxID); }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ESchedulerInitialization CScheduler::initialize()
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Scheduler initialize\n";
|
||||
|
||||
OV_ERROR_UNLESS_K(!this->isHoldingResources(), "Trying to configure a scheduler with non-empty resources", Kernel::ErrorType::BadCall,
|
||||
ESchedulerInitialization::Failed);
|
||||
|
||||
m_scenario = &m_rPlayer.getRuntimeScenarioManager().getScenario(m_scenarioID);
|
||||
|
||||
OV_ERROR_UNLESS_K(m_scenario, "Failed to find scenario with id " << m_scenarioID.str(), Kernel::ErrorType::ResourceNotFound,
|
||||
ESchedulerInitialization::Failed);
|
||||
|
||||
OV_ERROR_UNLESS_K(m_scenario->getNextBoxIdentifier(CIdentifier::undefined()) != CIdentifier::undefined(),
|
||||
"Cannot initialize scheduler with an empty scenario", Kernel::ErrorType::BadCall, ESchedulerInitialization::Failed);
|
||||
|
||||
CBoxSettingModifierVisitor boxSettingModifierVisitor(&this->getKernelContext().getConfigurationManager());
|
||||
|
||||
OV_ERROR_UNLESS_K(m_scenario->acceptVisitor(boxSettingModifierVisitor), "Failed to set box settings visitor for scenario with id "
|
||||
<< m_scenarioID.str(), Kernel::ErrorType::Internal, ESchedulerInitialization::Failed);
|
||||
|
||||
|
||||
{
|
||||
CIdentifier* listID = nullptr;
|
||||
size_t nbElems = 0;
|
||||
m_scenario->getBoxIdentifierList(&listID, &nbElems);
|
||||
|
||||
// Create sets of x and y positions, note that C++ sets are always ordered
|
||||
// We work with indexes rather than just positions because the positions are not bounded and can overflow
|
||||
std::set<int> xpositions;
|
||||
std::set<int> ypositions;
|
||||
for (size_t i = 0; i < nbElems; ++i)
|
||||
{
|
||||
const IBox* box = m_scenario->getBoxDetails(listID[i]);
|
||||
|
||||
if (box->hasAttribute(OV_AttributeId_Box_YCenterPosition))
|
||||
{
|
||||
try
|
||||
{
|
||||
int y = std::stoi(box->getAttributeValue(OV_AttributeId_Box_YCenterPosition).toASCIIString());
|
||||
ypositions.insert(y);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
OV_WARNING_K(
|
||||
"The Y position (" << box->getAttributeValue(OV_AttributeId_Box_YCenterPosition) << ") " << " in the Box " << listID[i] <<
|
||||
" is corrupted");
|
||||
}
|
||||
}
|
||||
if (box->hasAttribute(OV_AttributeId_Box_XCenterPosition))
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = std::stoi(box->getAttributeValue(OV_AttributeId_Box_XCenterPosition).toASCIIString());
|
||||
xpositions.insert(x);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
OV_WARNING_K(
|
||||
"The X position (" << box->getAttributeValue(OV_AttributeId_Box_XCenterPosition) << ") " << " in the Box " << listID[i] <<
|
||||
" is corrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nbElems; ++i)
|
||||
{
|
||||
const CIdentifier boxID = listID[i];
|
||||
const IBox* box = m_scenario->getBoxDetails(boxID);
|
||||
OV_ERROR_UNLESS_K(
|
||||
!m_scenario->hasOutdatedBox() || !this->getConfigurationManager().expandAsBoolean("${Kernel_AbortPlayerWhenBoxIsOutdated}", false),
|
||||
"Box [" << box->getName() << "] with class identifier [" << boxID.str() << "] should be updated",
|
||||
ErrorType::Internal, ESchedulerInitialization::Failed);
|
||||
|
||||
OV_ERROR_UNLESS_K(box->getAlgorithmClassIdentifier() != OVP_ClassId_BoxAlgorithm_Metabox,
|
||||
"Not expanded metabox with id [" << box->getAttributeValue(OVP_AttributeId_Metabox_ID) << "] detected in the scenario",
|
||||
ErrorType::Internal, ESchedulerInitialization::Failed);
|
||||
|
||||
const Plugins::IPluginObjectDesc* boxDesc = this->getPluginManager().getPluginObjectDescCreating(box->getAlgorithmClassIdentifier());
|
||||
|
||||
OV_ERROR_UNLESS_K(
|
||||
!(box->hasAttribute(OV_AttributeId_Box_Disabled) && this->getConfigurationManager().expandAsBoolean("${Kernel_AbortPlayerWhenBoxIsDisabled}",
|
||||
false)),
|
||||
"Disabled box [" << box->getName() << "] with class identifier [" << boxID.str() << "] detected in the scenario",
|
||||
ErrorType::Internal, ESchedulerInitialization::Failed);
|
||||
|
||||
if (!box->hasAttribute(OV_AttributeId_Box_Disabled))
|
||||
{
|
||||
OV_ERROR_UNLESS_K(boxDesc != nullptr,
|
||||
"Failed to create runtime box [" << box->getName() << "] with class identifier [" << boxID.str() << "]",
|
||||
ErrorType::BadResourceCreation, ESchedulerInitialization::Failed);
|
||||
|
||||
CSimulatedBox* simulatedBox = new CSimulatedBox(this->getKernelContext(), *this);
|
||||
simulatedBox->setScenarioIdentifier(m_scenarioID);
|
||||
simulatedBox->setBoxIdentifier(boxID);
|
||||
|
||||
|
||||
// Set priority so boxes execute in this order
|
||||
// - boxes with positive priority attribute set in descending order
|
||||
// - boxes in scenario from left to right and from top to bottom
|
||||
// - boxes with negative priority set in descending order
|
||||
int priority = 0;
|
||||
try
|
||||
{
|
||||
if (box->hasAttribute(OV_AttributeId_Box_Priority))
|
||||
{
|
||||
const int p = std::stoi(box->getAttributeValue(OV_AttributeId_Box_Priority).toASCIIString());
|
||||
|
||||
if (p < 0) { priority = -int((ypositions.size() << 15) + xpositions.size()) + p; }
|
||||
else { priority = p; }
|
||||
}
|
||||
else if (box->hasAttribute(OV_AttributeId_Box_YCenterPosition) && box->hasAttribute(OV_AttributeId_Box_XCenterPosition))
|
||||
{
|
||||
int x = std::stoi(box->getAttributeValue(OV_AttributeId_Box_XCenterPosition).toASCIIString());
|
||||
int y = std::stoi(box->getAttributeValue(OV_AttributeId_Box_YCenterPosition).toASCIIString());
|
||||
|
||||
const int xindex = int(std::distance(xpositions.begin(), xpositions.find(x)));
|
||||
const int yindex = int(std::distance(ypositions.begin(), ypositions.find(y)));
|
||||
priority = - ((yindex << 15) + xindex);
|
||||
}
|
||||
}
|
||||
catch (const std::exception&) { priority = 0; }
|
||||
|
||||
m_simulatedBoxes[std::make_pair(-priority, boxID)] = simulatedBox;
|
||||
m_simulatedBoxChronos[boxID].reset(m_frequency);
|
||||
}
|
||||
}
|
||||
m_scenario->releaseIdentifierList(listID);
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_K(!m_simulatedBoxes.empty(), "Cannot initialize scheduler with an empty scenario", Kernel::ErrorType::BadCall,
|
||||
ESchedulerInitialization::Failed);
|
||||
|
||||
|
||||
bool boxInitialization = true;
|
||||
for (auto it = m_simulatedBoxes.begin(); it != m_simulatedBoxes.end(); ++
|
||||
it)
|
||||
{
|
||||
if (auto simulatedBox = it->second)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Scheduled box : id = " << it->first.second << " priority = " << -it->first.first
|
||||
<< " name = " << simulatedBox->getName() << "\n";
|
||||
if (!translateException([&]() { return simulatedBox->initialize(); },
|
||||
std::bind(&CScheduler::handleException, this, simulatedBox, "Box initialization", std::placeholders::_1)))
|
||||
{
|
||||
boxInitialization = false;
|
||||
|
||||
// return as soon as possible
|
||||
// no need to keep on initializing boxes if a box failed to initialize
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_steps = 0;
|
||||
m_currentTime = 0;
|
||||
|
||||
m_oBenchmarkChrono.reset(m_frequency);
|
||||
|
||||
return (boxInitialization ? ESchedulerInitialization::Success : ESchedulerInitialization::Failed);
|
||||
}
|
||||
|
||||
bool CScheduler::uninitialize()
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Scheduler uninitialize\n";
|
||||
|
||||
bool boxUninitialization = true;
|
||||
for (auto it = m_simulatedBoxes.begin(); it != m_simulatedBoxes.end(); ++
|
||||
it)
|
||||
{
|
||||
if (auto simulatedBox = it->second)
|
||||
{
|
||||
if (!translateException([&]() { return simulatedBox->uninitialize(); },
|
||||
std::bind(&CScheduler::handleException, this, simulatedBox, "Box uninitialization", std::placeholders::_1)))
|
||||
{
|
||||
// do not break here because we want to try to
|
||||
// at least uninitialize other resources properly
|
||||
boxUninitialization = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = m_simulatedBoxes.begin(); it != m_simulatedBoxes.end(); ++it) { delete it->second; }
|
||||
m_simulatedBoxes.clear();
|
||||
|
||||
m_scenario = nullptr;
|
||||
|
||||
return boxUninitialization;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CScheduler::loop()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(this->isHoldingResources(), "Trying to use an uninitialized scheduler", Kernel::ErrorType::BadCall);
|
||||
|
||||
bool boxProcessing = true;
|
||||
m_oBenchmarkChrono.stepIn();
|
||||
for (auto it = m_simulatedBoxes.begin(); it != m_simulatedBoxes.end(); ++
|
||||
it)
|
||||
{
|
||||
CSimulatedBox* simulatedBox = it->second;
|
||||
|
||||
System::CChrono& simulatedBoxChrono = m_simulatedBoxChronos[it->first.second];
|
||||
|
||||
IBox* box = m_scenario->getBoxDetails(it->first.second);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(box, "Unable to get box details for box with id " << it->first.second.str(), Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
simulatedBoxChrono.stepIn();
|
||||
|
||||
if (!translateException([&]() { return this->processBox(simulatedBox, it->first.second); },
|
||||
std::bind(&CScheduler::handleException, this, simulatedBox, "Box processing", std::placeholders::_1)))
|
||||
{
|
||||
boxProcessing = false;
|
||||
|
||||
// break here because we do not want to keep on processing if one
|
||||
// box fails
|
||||
break;
|
||||
}
|
||||
|
||||
simulatedBoxChrono.stepOut();
|
||||
|
||||
if (simulatedBoxChrono.hasNewEstimation())
|
||||
{
|
||||
//IBox* box=m_scenario->getBoxDetails(it->first.second);
|
||||
box->addAttribute(OV_AttributeId_Box_ComputationTimeLastSecond, "");
|
||||
box->setAttributeValue(OV_AttributeId_Box_ComputationTimeLastSecond, CIdentifier(simulatedBoxChrono.getTotalStepInDuration()).toString());
|
||||
}
|
||||
}
|
||||
m_oBenchmarkChrono.stepOut();
|
||||
|
||||
if ((m_steps % m_frequency) == 0)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Debug
|
||||
<< "<" << LogColor_PushStateBit << LogColor_ForegroundBlue << "Scheduler" << LogColor_PopStateBit
|
||||
<< "::" << LogColor_PushStateBit << LogColor_ForegroundBlue << "elapsed time" << LogColor_PopStateBit << "> "
|
||||
<< m_steps / m_frequency << "s\n";
|
||||
}
|
||||
|
||||
if (m_oBenchmarkChrono.hasNewEstimation())
|
||||
{
|
||||
this->getLogManager() << LogLevel_Benchmark
|
||||
<< "<" << LogColor_PushStateBit << LogColor_ForegroundBlue << "Scheduler" << LogColor_PopStateBit
|
||||
<< "::" << LogColor_PushStateBit << LogColor_ForegroundBlue << "processor use" << LogColor_PopStateBit << "> "
|
||||
<< m_oBenchmarkChrono.getStepInPercentage() << "%\n";
|
||||
}
|
||||
|
||||
m_steps++;
|
||||
|
||||
m_currentTime = m_steps * CTime(m_frequency, 1LL).time();
|
||||
|
||||
return boxProcessing;
|
||||
}
|
||||
|
||||
bool CScheduler::processBox(CSimulatedBox* simulatedBox, const CIdentifier& boxID)
|
||||
{
|
||||
if (simulatedBox)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(simulatedBox->processClock(), "Process clock failed for box with id " << boxID.str(), Kernel::ErrorType::Internal);
|
||||
if (simulatedBox->isReadyToProcess())
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(simulatedBox->process(), "Process failed for box with id " << boxID.str(), Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
//if the box is muted we still have to erase chunks that arrives at the input
|
||||
std::map<size_t, std::list<CChunk>>& simulatedBoxInput = m_simulatedBoxInputs[boxID];
|
||||
for (auto it1 = simulatedBoxInput.begin(); it1 != simulatedBoxInput.end(); ++it1)
|
||||
{
|
||||
std::list<CChunk>& simulatedBoxInputChunkList = it1->second;
|
||||
for (auto it2 = simulatedBoxInputChunkList.begin(); it2 != simulatedBoxInputChunkList.end(); ++it2)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(simulatedBox->processInput(it1->first, *it2),
|
||||
"Process failed for box with id " << boxID.str() << " on input " << it1->first,
|
||||
ErrorType::Internal);
|
||||
|
||||
if (simulatedBox->isReadyToProcess())
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(simulatedBox->process(), "Process failed for box with id " << boxID.str(), Kernel::ErrorType::Internal);
|
||||
}
|
||||
}
|
||||
simulatedBoxInputChunkList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CScheduler::sendInput(const CChunk& chunk, const CIdentifier& boxId, const size_t index)
|
||||
{
|
||||
IBox* box = m_scenario->getBoxDetails(boxId);
|
||||
if (box->hasAttribute(OV_AttributeId_Box_Disabled)) { return true; }
|
||||
OV_ERROR_UNLESS_KRF(box, "Tried to send data chunk with invalid box identifier " << boxId.str(), Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(index < box->getInputCount(),
|
||||
"Tried to send data chunk with invalid input index " << index << " for box identifier" << boxId.str(),
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
auto it = m_simulatedBoxes.begin();
|
||||
while (it != m_simulatedBoxes.end() && it->first.second != boxId) { ++it; }
|
||||
|
||||
OV_ERROR_UNLESS_KRF(it != m_simulatedBoxes.end(),
|
||||
"Tried to send data chunk with invalid simulated box identifier " << boxId.str(),
|
||||
ErrorType::ResourceNotFound);
|
||||
CSimulatedBox* simulatedBox = it->second;
|
||||
|
||||
// use a fatal here because failing to meet this invariant
|
||||
// means there is a bug in the scheduler implementation
|
||||
OV_FATAL_UNLESS_K(simulatedBox, "Null box found for id " << boxId.str(), Kernel::ErrorType::BadValue);
|
||||
|
||||
// TODO: check if index does not overflow
|
||||
|
||||
m_simulatedBoxInputs[boxId][index].push_back(chunk);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t CScheduler::getCurrentLateness() const { return m_rPlayer.getCurrentSimulatedLateness(); }
|
||||
double CScheduler::getFastForwardMaximumFactor() const { return m_rPlayer.getFastForwardMaximumFactor(); }
|
||||
|
||||
void CScheduler::handleException(const CSimulatedBox* box, const char* errorHint, const std::exception& exception)
|
||||
{
|
||||
CIdentifier dstBoxID = CIdentifier::undefined();
|
||||
box->getBoxIdentifier(dstBoxID);
|
||||
|
||||
box->getLogManager() << LogLevel_Error << "Exception caught in box\n";
|
||||
box->getLogManager() << LogLevel_Error << " [name:" << box->getName() << "]\n";
|
||||
box->getLogManager() << LogLevel_Error << " [class identifier:" << dstBoxID << "]\n";
|
||||
box->getLogManager() << LogLevel_Error << " [hint: " << (errorHint ? errorHint : "no hint") << "]\n";
|
||||
box->getLogManager() << LogLevel_Error << " [cause:" << exception.what() << "]\n";
|
||||
|
||||
OV_ERROR_KRV("Caught exception: " << exception.what(), Kernel::ErrorType::ExceptionCaught);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
#include <system/ovCChrono.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
enum class ESchedulerInitialization { Success, BoxInitializationFailed, Failed };
|
||||
|
||||
class CSimulatedBox;
|
||||
class CChunk;
|
||||
class CPlayer;
|
||||
|
||||
class CScheduler final : public TKernelObject<IKernelObject>
|
||||
{
|
||||
public:
|
||||
|
||||
CScheduler(const IKernelContext& ctx, CPlayer& player);
|
||||
~CScheduler() override;
|
||||
|
||||
bool setScenario(const CIdentifier& scenarioID);
|
||||
bool setFrequency(uint64_t frequency);
|
||||
|
||||
bool isHoldingResources() const;
|
||||
|
||||
ESchedulerInitialization initialize();
|
||||
bool uninitialize();
|
||||
bool loop();
|
||||
|
||||
bool sendInput(const CChunk& chunk, const CIdentifier& boxId, size_t index);
|
||||
uint64_t getCurrentTime() const { return m_currentTime; }
|
||||
uint64_t getCurrentLateness() const;
|
||||
uint64_t getFrequency() const { return m_frequency; }
|
||||
uint64_t getStepDuration() const { return m_stepDuration; }
|
||||
double getCPUUsage() const { return (const_cast<System::CChrono&>(m_oBenchmarkChrono)).getStepInPercentage(); }
|
||||
double getFastForwardMaximumFactor() const;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IKernelObject>, OVK_ClassId_Kernel_Player_Scheduler)
|
||||
|
||||
CPlayer& getPlayer() const { return m_rPlayer; }
|
||||
|
||||
protected:
|
||||
|
||||
CPlayer& m_rPlayer;
|
||||
CIdentifier m_scenarioID = CIdentifier::undefined();
|
||||
IScenario* m_scenario = nullptr;
|
||||
size_t m_steps = 0;
|
||||
uint64_t m_frequency = 0;
|
||||
uint64_t m_stepDuration = 0;
|
||||
uint64_t m_currentTime = 0;
|
||||
|
||||
std::map<std::pair<int, CIdentifier>, CSimulatedBox*> m_simulatedBoxes;
|
||||
std::map<CIdentifier, System::CChrono> m_simulatedBoxChronos;
|
||||
std::map<CIdentifier, std::map<size_t, std::list<CChunk>>> m_simulatedBoxInputs;
|
||||
|
||||
private:
|
||||
|
||||
void handleException(const CSimulatedBox* box, const char* errorHint, const std::exception& exception);
|
||||
bool processBox(CSimulatedBox* simulatedBox, const CIdentifier& boxID);
|
||||
bool flattenScenario();
|
||||
System::CChrono m_oBenchmarkChrono;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,428 @@
|
||||
#include "ovkCSimulatedBox.h"
|
||||
#include "ovkCPlayer.h"
|
||||
#include "ovkCBoxAlgorithmContext.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
#define OV_IncorrectTime 0xffffffffffffffffULL
|
||||
|
||||
CSimulatedBox::CSimulatedBox(const IKernelContext& ctx, CScheduler& scheduler)
|
||||
: TKernelObject<IBoxIO>(ctx), m_scheduler(scheduler), m_lastClockActivationDate(OV_IncorrectTime) {}
|
||||
|
||||
CSimulatedBox::~CSimulatedBox() {}
|
||||
|
||||
bool CSimulatedBox::setScenarioIdentifier(const CIdentifier& scenarioID)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_scheduler.getPlayer().getRuntimeScenarioManager().isScenario(scenarioID),
|
||||
"Scenario with identifier " << scenarioID.str() << " does not exist",
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
m_scenario = &m_scheduler.getPlayer().getRuntimeScenarioManager().getScenario(scenarioID);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::getBoxIdentifier(CIdentifier& boxId) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_box, "Simulated box not initialized", Kernel::ErrorType::BadCall);
|
||||
|
||||
boxId = m_box->getIdentifier();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::setBoxIdentifier(const CIdentifier& boxId)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_scenario, "No scenario set", Kernel::ErrorType::BadCall);
|
||||
|
||||
m_box = m_scenario->getBoxDetails(boxId);
|
||||
return m_box != nullptr;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::initialize()
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_box, "Simulated box not initialized", Kernel::ErrorType::BadCall);
|
||||
OV_ERROR_UNLESS_KRF(m_scenario, "No scenario set", Kernel::ErrorType::BadCall);
|
||||
|
||||
m_chunkConsistencyChecking = this->getConfigurationManager().expandAsBoolean("${Kernel_CheckChunkConsistency}", true);
|
||||
m_Inputs.resize(m_box->getInputCount());
|
||||
m_Outputs.resize(m_box->getOutputCount());
|
||||
m_CurrentOutputs.resize(m_box->getOutputCount());
|
||||
m_LastOutputStartTimes.resize(m_box->getOutputCount(), 0);
|
||||
m_LastOutputEndTimes.resize(m_box->getOutputCount(), 0);
|
||||
|
||||
m_lastClockActivationDate = OV_IncorrectTime;
|
||||
m_clockFrequency = 0;
|
||||
m_clockActivationStep = 0;
|
||||
|
||||
m_boxAlgorithm = getPluginManager().createBoxAlgorithm(m_box->getAlgorithmClassIdentifier(), nullptr);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(m_boxAlgorithm, "Could not create box algorithm with class id " << m_box->getAlgorithmClassIdentifier().str(),
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
{
|
||||
CBoxAlgorithmCtx context(getKernelContext(), this, m_box);
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_boxAlgorithm->initialize(context), "Box algorithm <" << m_box->getName() << "> initialization failed",
|
||||
Kernel::ErrorType::Internal);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::uninitialize()
|
||||
{
|
||||
if (!m_boxAlgorithm) { return true; }
|
||||
|
||||
{
|
||||
CBoxAlgorithmCtx context(getKernelContext(), this, m_box);
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_boxAlgorithm->uninitialize(context), "Box algorithm <" << m_box->getName() << "> uninitialization failed",
|
||||
ErrorType::Internal);
|
||||
}
|
||||
}
|
||||
|
||||
getPluginManager().releasePluginObject(m_boxAlgorithm);
|
||||
m_boxAlgorithm = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::processClock()
|
||||
{
|
||||
{
|
||||
CBoxAlgorithmCtx context(getKernelContext(), this, m_box);
|
||||
{
|
||||
const uint64_t newFreq = m_boxAlgorithm->getClockFrequency(context);
|
||||
if (newFreq == 0)
|
||||
{
|
||||
m_clockActivationStep = OV_IncorrectTime;
|
||||
m_lastClockActivationDate = OV_IncorrectTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(newFreq <= m_scheduler.getFrequency()<<32,
|
||||
"Box " << m_box->getName() << " requested higher clock frequency ("
|
||||
<< newFreq << " == " << CTime(newFreq).toSeconds() << "hz) " << "than what the scheduler can handle ("
|
||||
<< (m_scheduler.getFrequency()<<32) << " == " << CTime(m_scheduler.getFrequency()<<32).toSeconds() << "hz)",
|
||||
ErrorType::BadConfig);
|
||||
|
||||
// note: 1LL should be left shifted 64 bits but this
|
||||
// would result in an integer over shift (the one
|
||||
// would exit). Thus the left shift of 63 bits
|
||||
// and the left shift of 1 bit after the division
|
||||
m_clockActivationStep = ((1ULL << 63) / newFreq) << 1;
|
||||
}
|
||||
m_clockFrequency = newFreq;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_clockFrequency != 0) && (m_lastClockActivationDate == OV_IncorrectTime || m_scheduler.getCurrentTime() - m_lastClockActivationDate >=
|
||||
m_clockActivationStep))
|
||||
{
|
||||
CBoxAlgorithmCtx context(getKernelContext(), this, m_box);
|
||||
{
|
||||
if (m_lastClockActivationDate == OV_IncorrectTime) { m_lastClockActivationDate = m_scheduler.getCurrentTime(); }
|
||||
else { m_lastClockActivationDate = m_lastClockActivationDate + m_clockActivationStep; }
|
||||
|
||||
CMessageClock message;
|
||||
message.setTime(m_lastClockActivationDate);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(m_boxAlgorithm->processClock(context, message),
|
||||
"Box algorithm <" << m_box->getName() << "> processClock() function failed", Kernel::ErrorType::Internal);
|
||||
|
||||
m_readyToProcess |= context.isAlgorithmReadyToProcess();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::processInput(const size_t index, const CChunk& chunk)
|
||||
{
|
||||
m_Inputs[index].push_back(chunk);
|
||||
|
||||
{
|
||||
CBoxAlgorithmCtx context(getKernelContext(), this, m_box);
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_boxAlgorithm->processInput(context, index),
|
||||
"Box algorithm <" << m_box->getName() << "> processInput() function failed", Kernel::ErrorType::Internal);
|
||||
}
|
||||
m_readyToProcess |= context.isAlgorithmReadyToProcess();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::process()
|
||||
{
|
||||
if (!m_readyToProcess) { return true; }
|
||||
{
|
||||
CBoxAlgorithmCtx context(getKernelContext(), this, m_box);
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_boxAlgorithm->process(context), "Box algorithm <" << m_box->getName() << "> processInput function failed",
|
||||
ErrorType::Internal);
|
||||
}
|
||||
}
|
||||
|
||||
// perform output sending
|
||||
{
|
||||
CIdentifier* listID = nullptr;
|
||||
size_t nbElems = 0;
|
||||
m_scenario->getLinkIdentifierFromBoxList(m_box->getIdentifier(), &listID, &nbElems);
|
||||
for (size_t i = 0; i < nbElems; ++i)
|
||||
{
|
||||
const ILink* link = m_scenario->getLinkDetails(listID[i]);
|
||||
if (link)
|
||||
{
|
||||
CIdentifier dstBoxID = link->getTargetBoxIdentifier();
|
||||
const size_t dstBoxInputIdx = link->getTargetBoxInputIndex();
|
||||
|
||||
const size_t sourceOutputIdx = link->getSourceBoxOutputIndex();
|
||||
for (auto& chunk : m_Outputs[sourceOutputIdx]) { m_scheduler.sendInput(chunk, dstBoxID, dstBoxInputIdx); }
|
||||
}
|
||||
}
|
||||
m_scenario->releaseIdentifierList(listID);
|
||||
}
|
||||
|
||||
// perform input cleaning
|
||||
auto socketIterator = m_Inputs.begin();
|
||||
while (socketIterator != m_Inputs.end())
|
||||
{
|
||||
auto inputChunkIterator = socketIterator->begin();
|
||||
while (inputChunkIterator != socketIterator->end())
|
||||
{
|
||||
if (inputChunkIterator->isDeprecated()) { inputChunkIterator = socketIterator->erase(inputChunkIterator); }
|
||||
else { ++inputChunkIterator; }
|
||||
}
|
||||
++socketIterator;
|
||||
}
|
||||
|
||||
// flushes sent output chunks
|
||||
for (auto& socket : m_Outputs) { socket.resize(0); }
|
||||
|
||||
// discards waiting output chunks
|
||||
for (const auto& chunk : m_CurrentOutputs)
|
||||
{
|
||||
OV_FATAL_UNLESS_K(chunk.getBuffer().getSize() == 0, "Output buffer filled but not marked as ready to send. Possible loss of data.",
|
||||
ErrorType::Internal);
|
||||
}
|
||||
|
||||
m_readyToProcess = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatedBox::isReadyToProcess() const { return m_readyToProcess; }
|
||||
|
||||
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
||||
// - --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- -
|
||||
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
||||
|
||||
CString CSimulatedBox::getName() const { return m_box->getName(); }
|
||||
|
||||
const IScenario& CSimulatedBox::getScenario() const { return *m_scenario; }
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
size_t CSimulatedBox::getInputChunkCount(const size_t index) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(index < m_Inputs.size(),
|
||||
"Input index = [" << index << "] is out of range (max index = [" << m_Inputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return size_t(m_Inputs[index].size());
|
||||
}
|
||||
|
||||
bool CSimulatedBox::getInputChunk(const size_t inputIdx, const size_t chunkIdx, uint64_t& startTime, uint64_t& endTime, size_t& size,
|
||||
const uint8_t*& buffer) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(inputIdx < m_Inputs.size(),
|
||||
"Input index = [" << inputIdx << "] is out of range (max index = [" << m_Inputs.size() - 1 << "])", Kernel::ErrorType::OutOfBound);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(chunkIdx < m_Inputs[inputIdx].size(),
|
||||
"Input chunk index = [" << chunkIdx << "] is out of range (max index = [" << m_Inputs[inputIdx].size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
const CChunk& chunk = m_Inputs[inputIdx][chunkIdx];
|
||||
startTime = chunk.getStartTime();
|
||||
endTime = chunk.getEndTime();
|
||||
size = chunk.getBuffer().getSize();
|
||||
buffer = chunk.getBuffer().getDirectPointer();
|
||||
return true;
|
||||
}
|
||||
|
||||
const IMemoryBuffer* CSimulatedBox::getInputChunk(const size_t inputIdx, const size_t chunkIdx) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRN(inputIdx < m_Inputs.size(),
|
||||
"Input index = [" << inputIdx << "] is out of range (max index = [" << m_Inputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
OV_ERROR_UNLESS_KRN(chunkIdx < m_Inputs[inputIdx].size(),
|
||||
"Input chunk index = [" << chunkIdx << "] is out of range (max index = [" << m_Inputs[inputIdx].size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return &(m_Inputs[inputIdx][chunkIdx]).getBuffer();
|
||||
}
|
||||
|
||||
uint64_t CSimulatedBox::getInputChunkStartTime(const size_t inputIdx, const size_t chunkIdx) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRZ(inputIdx < m_Inputs.size(),
|
||||
"Input index = [" << inputIdx << "] is out of range (max index = [" << m_Inputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
OV_ERROR_UNLESS_KRZ(chunkIdx < m_Inputs[inputIdx].size(),
|
||||
"Input chunk index = [" << chunkIdx << "] is out of range (max index = [" << m_Inputs[inputIdx].size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
const CChunk& chunk = m_Inputs[inputIdx][chunkIdx];
|
||||
return chunk.getStartTime();
|
||||
}
|
||||
|
||||
uint64_t CSimulatedBox::getInputChunkEndTime(const size_t inputIdx, const size_t chunkIdx) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRZ(inputIdx < m_Inputs.size(),
|
||||
"Input index = [" << inputIdx << "] is out of range (max index = [" << m_Inputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
OV_ERROR_UNLESS_KRZ(chunkIdx < m_Inputs[inputIdx].size(),
|
||||
"Input chunk index = [" << chunkIdx << "] is out of range (max index = [" << m_Inputs[inputIdx].size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
const CChunk& chunk = m_Inputs[inputIdx][chunkIdx];
|
||||
return chunk.getEndTime();
|
||||
}
|
||||
|
||||
bool CSimulatedBox::markInputAsDeprecated(const size_t inputIdx, const size_t chunkIdx)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRZ(inputIdx < m_Inputs.size(),
|
||||
"Input index = [" << inputIdx << "] is out of range (max index = [" << m_Inputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
OV_ERROR_UNLESS_KRZ(chunkIdx < m_Inputs[inputIdx].size(),
|
||||
"Input chunk index = [" << chunkIdx << "] is out of range (max index = [" << m_Inputs[inputIdx].size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
m_Inputs[inputIdx][chunkIdx].markAsDeprecated(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
size_t CSimulatedBox::getOutputChunkSize(const size_t outputIdx) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRZ(outputIdx < m_CurrentOutputs.size(),
|
||||
"Output index = [" << outputIdx << "] is out of range (max index = [" << m_CurrentOutputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return m_CurrentOutputs[outputIdx].getBuffer().getSize();
|
||||
}
|
||||
|
||||
bool CSimulatedBox::setOutputChunkSize(const size_t outputIdx, const size_t size, const bool discard)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(outputIdx < m_CurrentOutputs.size(),
|
||||
"Output index = [" << outputIdx << "] is out of range (max index = [" << m_CurrentOutputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return m_CurrentOutputs[outputIdx].getBuffer().setSize(size, discard);
|
||||
}
|
||||
|
||||
uint8_t* CSimulatedBox::getOutputChunkBuffer(const size_t outputIdx)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRN(outputIdx < m_CurrentOutputs.size(),
|
||||
"Output index = [" << outputIdx << "] is out of range (max index = [" << m_CurrentOutputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return m_CurrentOutputs[outputIdx].getBuffer().getDirectPointer();
|
||||
}
|
||||
|
||||
bool CSimulatedBox::appendOutputChunkData(const size_t outputIdx, const uint8_t* buffer, const size_t size)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(outputIdx < m_CurrentOutputs.size(),
|
||||
"Output index = [" << outputIdx << "] is out of range (max index = [" << m_CurrentOutputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return m_CurrentOutputs[outputIdx].getBuffer().append(buffer, size);
|
||||
}
|
||||
|
||||
IMemoryBuffer* CSimulatedBox::getOutputChunk(const size_t outputIdx)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRN(outputIdx < m_CurrentOutputs.size(),
|
||||
"Output index = [" << outputIdx << "] is out of range (max index = [" << m_CurrentOutputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return &m_CurrentOutputs[outputIdx].getBuffer();
|
||||
}
|
||||
|
||||
bool CSimulatedBox::markOutputAsReadyToSend(const size_t outputIdx, const uint64_t startTime, const uint64_t endTime)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(outputIdx < m_CurrentOutputs.size(),
|
||||
"Output index = [" << outputIdx << "] is out of range (max index = [" << m_CurrentOutputs.size() - 1 << "])",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
if (m_chunkConsistencyChecking)
|
||||
{
|
||||
bool isConsistent = true;
|
||||
const char* specificMessage = nullptr;
|
||||
|
||||
// checks chunks consistency
|
||||
CIdentifier type;
|
||||
m_box->getOutputType(outputIdx, type);
|
||||
if (type == OV_TypeId_Stimulations)
|
||||
{
|
||||
if (m_LastOutputEndTimes[outputIdx] != startTime)
|
||||
{
|
||||
isConsistent = false;
|
||||
specificMessage = "'Stimulations' streams should have continuously dated chunks";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_LastOutputEndTimes[outputIdx] > endTime)
|
||||
{
|
||||
isConsistent = false;
|
||||
specificMessage = "Current 'end time' can not be earlier than previous 'end time'";
|
||||
}
|
||||
|
||||
if (m_LastOutputStartTimes[outputIdx] > startTime)
|
||||
{
|
||||
isConsistent = false;
|
||||
specificMessage = "Current 'start time' can not be earlier than previous 'start time'";
|
||||
}
|
||||
|
||||
if (!isConsistent)
|
||||
{
|
||||
this->getLogManager() << m_chunkConsistencyCheckingLogLevel << "Box <" << m_box->getName() << "> sends inconsistent chunk dates on output [" <<
|
||||
outputIdx << "] (current chunk dates are [" << startTime << "," << endTime << "] whereas previous chunk dates were [" <<
|
||||
m_LastOutputStartTimes[outputIdx] << "," << m_LastOutputEndTimes[outputIdx] << "])\n";
|
||||
if (specificMessage) { this->getLogManager() << m_chunkConsistencyCheckingLogLevel << specificMessage << "\n"; }
|
||||
this->getLogManager() << m_chunkConsistencyCheckingLogLevel << "Please report to box author and attach your scenario\n";
|
||||
this->getLogManager() << LogLevel_Trace << "Previous warning can be disabled setting Kernel_CheckChunkConsistency to false\n";
|
||||
m_chunkConsistencyCheckingLogLevel = LogLevel_Trace;
|
||||
}
|
||||
|
||||
// sets last times
|
||||
m_LastOutputStartTimes[outputIdx] = startTime;
|
||||
m_LastOutputEndTimes[outputIdx] = endTime;
|
||||
}
|
||||
|
||||
// sets start and end time
|
||||
m_CurrentOutputs[outputIdx].setStartTime(std::min(startTime, endTime));
|
||||
m_CurrentOutputs[outputIdx].setEndTime(std::max(startTime, endTime));
|
||||
|
||||
// copies chunk
|
||||
m_Outputs[outputIdx].push_back(m_CurrentOutputs[outputIdx]);
|
||||
|
||||
// resets chunk size
|
||||
m_CurrentOutputs[outputIdx].getBuffer().setSize(0, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
#include "ovkCBuffer.h"
|
||||
|
||||
#include <system/ovCChrono.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScheduler;
|
||||
|
||||
class CChunk
|
||||
{
|
||||
public:
|
||||
|
||||
CChunk() { }
|
||||
|
||||
CChunk(const CChunk& chunk) : m_buffer(chunk.m_buffer), m_startTime(chunk.m_startTime), m_endTime(chunk.m_endTime) { }
|
||||
|
||||
const CBuffer& getBuffer() const { return m_buffer; }
|
||||
uint64_t getStartTime() const { return m_startTime; }
|
||||
uint64_t getEndTime() const { return m_endTime; }
|
||||
bool isDeprecated() const { return m_isDeprecated; }
|
||||
CBuffer& getBuffer() { return m_buffer; }
|
||||
|
||||
bool setStartTime(const uint64_t startTime)
|
||||
{
|
||||
m_startTime = startTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setEndTime(const uint64_t endTime)
|
||||
{
|
||||
m_endTime = endTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool markAsDeprecated(const bool isDeprecated)
|
||||
{
|
||||
m_isDeprecated = isDeprecated;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
CBuffer m_buffer;
|
||||
uint64_t m_startTime = 0;
|
||||
uint64_t m_endTime = 0;
|
||||
bool m_isDeprecated = false;
|
||||
};
|
||||
|
||||
class CSimulatedBox final : public TKernelObject<IBoxIO>
|
||||
{
|
||||
public:
|
||||
|
||||
CSimulatedBox(const IKernelContext& ctx, CScheduler& scheduler);
|
||||
~CSimulatedBox() override;
|
||||
|
||||
bool setScenarioIdentifier(const CIdentifier& scenarioID);
|
||||
bool getBoxIdentifier(CIdentifier& boxId) const;
|
||||
bool setBoxIdentifier(const CIdentifier& boxId);
|
||||
|
||||
bool initialize();
|
||||
bool uninitialize();
|
||||
|
||||
bool processClock();
|
||||
bool processInput(const size_t index, const CChunk& chunk);
|
||||
bool process();
|
||||
bool isReadyToProcess() const;
|
||||
|
||||
CString getName() const;
|
||||
const IScenario& getScenario() const;
|
||||
|
||||
/** \name IBoxIO inputs handling */
|
||||
//@{
|
||||
size_t getInputChunkCount(const size_t index) const override;
|
||||
bool getInputChunk(const size_t inputIdx, const size_t chunkIdx, uint64_t& startTime, uint64_t& endTime, size_t& size,
|
||||
const uint8_t*& buffer) const override;
|
||||
const IMemoryBuffer* getInputChunk(const size_t inputIdx, const size_t chunkIdx) const override;
|
||||
uint64_t getInputChunkStartTime(const size_t inputIdx, const size_t chunkIdx) const override;
|
||||
uint64_t getInputChunkEndTime(const size_t inputIdx, const size_t chunkIdx) const override;
|
||||
bool markInputAsDeprecated(const size_t inputIdx, const size_t chunkIdx) override;
|
||||
//@}
|
||||
|
||||
/** \name IBoxIO outputs handling */
|
||||
//@{
|
||||
size_t getOutputChunkSize(const size_t outputIdx) const override;
|
||||
bool setOutputChunkSize(const size_t outputIdx, const size_t size, const bool discard = true) override;
|
||||
uint8_t* getOutputChunkBuffer(const size_t outputIdx) override;
|
||||
bool appendOutputChunkData(const size_t outputIdx, const uint8_t* buffer, const size_t size) override;
|
||||
IMemoryBuffer* getOutputChunk(const size_t outputIdx) override;
|
||||
bool markOutputAsReadyToSend(const size_t outputIdx, const uint64_t startTime, const uint64_t endTime) override;
|
||||
//@}
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IBoxIO>, OVK_ClassId_Kernel_Player_SimulatedBox)
|
||||
|
||||
CScheduler& getScheduler() const { return m_scheduler; }
|
||||
|
||||
protected:
|
||||
|
||||
bool m_readyToProcess = false;
|
||||
bool m_chunkConsistencyChecking = false;
|
||||
ELogLevel m_chunkConsistencyCheckingLogLevel = LogLevel_Warning;
|
||||
|
||||
Plugins::IBoxAlgorithm* m_boxAlgorithm = nullptr;
|
||||
const IScenario* m_scenario = nullptr;
|
||||
const IBox* m_box = nullptr;
|
||||
CScheduler& m_scheduler;
|
||||
|
||||
uint64_t m_lastClockActivationDate = 0;
|
||||
uint64_t m_clockFrequency = 0;
|
||||
uint64_t m_clockActivationStep = 0;
|
||||
|
||||
public:
|
||||
|
||||
std::vector<std::deque<CChunk>> m_Inputs;
|
||||
std::vector<std::deque<CChunk>> m_Outputs;
|
||||
std::vector<CChunk> m_CurrentOutputs;
|
||||
std::vector<uint64_t> m_LastOutputStartTimes;
|
||||
std::vector<uint64_t> m_LastOutputEndTimes;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+411
@@ -0,0 +1,411 @@
|
||||
#include "ovkCPluginManager.h"
|
||||
#include "ovkCPluginModule.h"
|
||||
|
||||
#include <fs/IEntryEnumerator.h>
|
||||
#include <fs/Files.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../tools/ovkSBoxProto.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CPluginManagerEntryEnumeratorCallBack final : public TKernelObject<IObject>, public FS::IEntryEnumeratorCallBack
|
||||
{
|
||||
public:
|
||||
|
||||
CPluginManagerEntryEnumeratorCallBack(const IKernelContext& ctx, std::vector<IPluginModule*>& pluginModule,
|
||||
std::map<Plugins::IPluginObjectDesc*, IPluginModule*>& pluginObjectDesc, bool& haveAllPluginsLoadedCorrectly)
|
||||
: TKernelObject<IObject>(ctx), m_rPluginManager(ctx.getPluginManager()), m_rPluginModule(pluginModule),
|
||||
m_rPluginObjectDesc(pluginObjectDesc), m_HaveAllPluginsLoadedCorrectly(haveAllPluginsLoadedCorrectly) { }
|
||||
|
||||
bool callback(FS::IEntryEnumerator::IEntry& entry, FS::IEntryEnumerator::IAttributes& /*attributes*/) override
|
||||
{
|
||||
for (auto& pluginModule : m_rPluginModule)
|
||||
{
|
||||
CString name;
|
||||
if (!pluginModule->getFileName(name)) { return true; }
|
||||
|
||||
if (FS::Files::equals(entry.getName(), name.toASCIIString()))
|
||||
{
|
||||
OV_WARNING_K(std::string("Module [") + entry.getName() + "] has already been loaded");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
IPluginModule* module = new CPluginModule(this->getKernelContext());
|
||||
CString loadError;
|
||||
if (!module->load(entry.getName(), &loadError))
|
||||
{
|
||||
delete module;
|
||||
OV_WARNING_K(std::string("File [") + entry.getName() + "] is not a plugin module (error:" + loadError.toASCIIString() + ")");
|
||||
m_HaveAllPluginsLoadedCorrectly = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!module->initialize())
|
||||
{
|
||||
module->uninitialize();
|
||||
module->unload();
|
||||
delete module;
|
||||
OV_WARNING_K(std::string("Module [") + entry.getName() + "] did not initialize correctly");
|
||||
m_HaveAllPluginsLoadedCorrectly = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pluginObjectDescAdded = false;
|
||||
size_t index = 0;
|
||||
size_t n = 0;
|
||||
Plugins::IPluginObjectDesc* desc = nullptr;
|
||||
while (module->getPluginObjectDescription(index, desc))
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for (const auto& pluginObjectDesc : m_rPluginObjectDesc)
|
||||
{
|
||||
if (pluginObjectDesc.first->getClassIdentifier() == desc->getClassIdentifier())
|
||||
{
|
||||
OV_WARNING_K("Duplicate plugin object descriptor class identifier [" + pluginObjectDesc.first->getName()
|
||||
+ "] and [" + desc->getName() + "]... second one is ignored");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (!pluginObjectDescAdded)
|
||||
{
|
||||
m_rPluginModule.push_back(module);
|
||||
pluginObjectDescAdded = true;
|
||||
}
|
||||
m_rPluginObjectDesc[desc] = module;
|
||||
n++;
|
||||
}
|
||||
index++;
|
||||
desc = nullptr;
|
||||
}
|
||||
|
||||
OV_WARNING_UNLESS_K(pluginObjectDescAdded,
|
||||
std::string("No 'plugin object descriptor' found from [") + entry.getName() + "] even if it looked like a plugin module\n");
|
||||
|
||||
this->getLogManager() << LogLevel_Info << "Added " << n << " plugin object descriptor(s) from [" << CString(entry.getName()) << "]\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IObject>, CIdentifier::undefined())
|
||||
|
||||
protected:
|
||||
|
||||
IPluginManager& m_rPluginManager;
|
||||
std::vector<IPluginModule*>& m_rPluginModule;
|
||||
std::map<Plugins::IPluginObjectDesc*, IPluginModule*>& m_rPluginObjectDesc;
|
||||
bool& m_HaveAllPluginsLoadedCorrectly;
|
||||
};
|
||||
|
||||
CPluginManager::~CPluginManager()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
for (auto& pluginObjectVector : m_pluginObjects)
|
||||
{
|
||||
for (auto& pluginObject : pluginObjectVector.second)
|
||||
{
|
||||
OV_WARNING_K(
|
||||
"Trying to release plugin object with class id " + pluginObject->getClassIdentifier().str() + " and plugin object descriptor "
|
||||
+ pluginObjectVector.first->getName().toASCIIString() + " at plugin manager destruction time");
|
||||
pluginObject->release();
|
||||
}
|
||||
}
|
||||
m_pluginObjects.clear();
|
||||
|
||||
for (auto& pluginObjectDesc : m_pluginObjectDescs) { pluginObjectDesc.first->release(); }
|
||||
m_pluginObjectDescs.clear();
|
||||
|
||||
for (auto k = m_pluginModules.begin(); k != m_pluginModules.end(); ++k)
|
||||
{
|
||||
this->TKernelObject<IPluginManager>::getLogManager() << LogLevel_Trace << "Releasing plugin module with class id " << (*k)->getClassIdentifier() <<
|
||||
"\n";
|
||||
(*k)->uninitialize();
|
||||
delete (*k);
|
||||
}
|
||||
m_pluginModules.clear();
|
||||
}
|
||||
|
||||
bool CPluginManager::addPluginsFromFiles(const CString& rFileNameWildCard)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
this->getLogManager() << LogLevel_Info << "Adding plugins from [" << rFileNameWildCard << "]\n";
|
||||
|
||||
bool res = true;
|
||||
bool haveAllPluginsLoadedCorrectly = true;
|
||||
CPluginManagerEntryEnumeratorCallBack cb(this->getKernelContext(), m_pluginModules, m_pluginObjectDescs, haveAllPluginsLoadedCorrectly);
|
||||
FS::IEntryEnumerator* entryEnumerator = createEntryEnumerator(cb);
|
||||
|
||||
std::stringstream ss(rFileNameWildCard.toASCIIString());
|
||||
std::string path;
|
||||
|
||||
while (getline(ss, path, ';'))
|
||||
{
|
||||
res &= entryEnumerator->enumerate(path.c_str());
|
||||
if (!res) { break; }
|
||||
}
|
||||
|
||||
entryEnumerator->release();
|
||||
|
||||
// Just return res. Error handling is performed within CPluginManagerEntryEnumeratorCallBack.
|
||||
return res && haveAllPluginsLoadedCorrectly;
|
||||
}
|
||||
|
||||
bool CPluginManager::registerPluginDesc(const Plugins::IPluginObjectDesc& rPluginObjectDesc)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
m_pluginObjectDescs[const_cast<Plugins::IPluginObjectDesc*>(&rPluginObjectDesc)] = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CPluginManager::getNextPluginObjectDescIdentifier(const CIdentifier& previousID) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
bool foundPrevious = (previousID == CIdentifier::undefined());
|
||||
for (const auto& elem : m_pluginObjectDescs)
|
||||
{
|
||||
if (!foundPrevious) { if (elem.first->getClassIdentifier() == previousID) { foundPrevious = true; } }
|
||||
else { return elem.first->getClassIdentifier(); }
|
||||
}
|
||||
return CIdentifier::undefined();
|
||||
}
|
||||
|
||||
CIdentifier CPluginManager::getNextPluginObjectDescIdentifier(const CIdentifier& previousID, const CIdentifier& baseClassID) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
bool foundPrevious = (previousID == CIdentifier::undefined());
|
||||
for (const auto& elem : m_pluginObjectDescs)
|
||||
{
|
||||
if (!foundPrevious) { if (elem.first->getClassIdentifier() == previousID) { foundPrevious = true; } }
|
||||
else { if (elem.first->isDerivedFromClass(baseClassID)) { return elem.first->getClassIdentifier(); } }
|
||||
}
|
||||
return CIdentifier::undefined();
|
||||
}
|
||||
|
||||
bool CPluginManager::canCreatePluginObject(const CIdentifier& classID)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
// this->getLogManager() << Kernel::LogLevel_Debug << "Searching if can build plugin object\n";
|
||||
|
||||
return std::any_of(m_pluginObjectDescs.begin(), m_pluginObjectDescs.end(), [classID](const std::pair<Plugins::IPluginObjectDesc*, IPluginModule*>& v)
|
||||
{
|
||||
return v.first->getCreatedClass() == classID;
|
||||
});
|
||||
}
|
||||
|
||||
const Plugins::IPluginObjectDesc* CPluginManager::getPluginObjectDesc(const CIdentifier& classID) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
// this->getLogManager() << Kernel::LogLevel_Debug << "Searching plugin object descriptor\n";
|
||||
|
||||
for (auto& pluginObject : m_pluginObjectDescs) { if (pluginObject.first->getClassIdentifier() == classID) { return pluginObject.first; } }
|
||||
|
||||
this->getLogManager() << LogLevel_Debug << "Plugin object descriptor class identifier " << classID << " not found\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Plugins::IPluginObjectDesc* CPluginManager::getPluginObjectDescCreating(const CIdentifier& classID) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
// this->getLogManager() << Kernel::LogLevel_Debug << "Searching plugin object descriptor\n";
|
||||
|
||||
const auto elem = std::find_if(m_pluginObjectDescs.begin(), m_pluginObjectDescs.end(),
|
||||
[classID](const std::pair<Plugins::IPluginObjectDesc*, IPluginModule*>& v) { return v.first->getCreatedClass() == classID; });
|
||||
if (elem != m_pluginObjectDescs.end()) { return elem->first; }
|
||||
this->getLogManager() << LogLevel_Debug << "Plugin object descriptor class identifier " << classID << " not found\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CIdentifier CPluginManager::getPluginObjectHashValue(const CIdentifier& classID) const
|
||||
{
|
||||
// std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
const Plugins::IPluginObjectDesc* pluginObjectDesc = this->getPluginObjectDescCreating(classID);
|
||||
const Plugins::IBoxAlgorithmDesc* boxAlgorithmDesc = dynamic_cast<const Plugins::IBoxAlgorithmDesc*>(pluginObjectDesc);
|
||||
if (boxAlgorithmDesc)
|
||||
{
|
||||
SBoxProto prototype(getKernelContext().getTypeManager());
|
||||
boxAlgorithmDesc->getBoxPrototype(prototype);
|
||||
return prototype.m_hash;
|
||||
}
|
||||
return CIdentifier::undefined();
|
||||
}
|
||||
|
||||
CIdentifier CPluginManager::getPluginObjectHashValue(const Plugins::IBoxAlgorithmDesc& boxAlgorithmDesc) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
SBoxProto prototype(getKernelContext().getTypeManager());
|
||||
boxAlgorithmDesc.getBoxPrototype(prototype);
|
||||
return prototype.m_hash;
|
||||
}
|
||||
|
||||
bool CPluginManager::isPluginObjectFlaggedAsDeprecated(const CIdentifier& classID) const
|
||||
{
|
||||
// std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
const Plugins::IPluginObjectDesc* pluginObjectDesc = this->getPluginObjectDescCreating(classID);
|
||||
const Plugins::IBoxAlgorithmDesc* boxAlgorithmDesc = dynamic_cast<const Plugins::IBoxAlgorithmDesc*>(pluginObjectDesc);
|
||||
if (boxAlgorithmDesc)
|
||||
{
|
||||
SBoxProto prototype(getKernelContext().getTypeManager());
|
||||
boxAlgorithmDesc->getBoxPrototype(prototype);
|
||||
return prototype.m_isDeprecated;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Plugins::IPluginObject* CPluginManager::createPluginObject(const CIdentifier& classID)
|
||||
{
|
||||
return createPluginObjectT<Plugins::IPluginObject, Plugins::IPluginObjectDesc>(classID, nullptr);
|
||||
}
|
||||
|
||||
bool CPluginManager::releasePluginObject(Plugins::IPluginObject* pluginObject)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Debug << "Releasing plugin object\n";
|
||||
|
||||
OV_ERROR_UNLESS_KRF(pluginObject, "Plugin object value is null", Kernel::ErrorType::BadProcessing);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
for (auto& elem : m_pluginObjects)
|
||||
{
|
||||
auto pluginObjectIt = std::find(elem.second.begin(), elem.second.end(), pluginObject);
|
||||
if (pluginObjectIt != elem.second.end())
|
||||
{
|
||||
elem.second.erase(pluginObjectIt);
|
||||
pluginObject->release();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OV_ERROR_KRF("Plugin object has not been created by this plugin manager (class id was " << pluginObject->getClassIdentifier().str() << ")",
|
||||
ErrorType::ResourceNotFound);
|
||||
}
|
||||
|
||||
Plugins::IAlgorithm* CPluginManager::createAlgorithm(const CIdentifier& classID, const Plugins::IAlgorithmDesc** algorithmDesc)
|
||||
{
|
||||
return createPluginObjectT<Plugins::IAlgorithm, Plugins::IAlgorithmDesc>(classID, algorithmDesc);
|
||||
}
|
||||
|
||||
Plugins::IAlgorithm* CPluginManager::createAlgorithm(const Plugins::IAlgorithmDesc& algorithmDesc)
|
||||
{
|
||||
Plugins::IAlgorithmDesc* desc = const_cast<Plugins::IAlgorithmDesc*>(&algorithmDesc);
|
||||
Plugins::IPluginObject* pluginObject = desc->create();
|
||||
|
||||
OV_ERROR_UNLESS_KRN(pluginObject,
|
||||
"Could not create plugin object from " << algorithmDesc.getName() << " plugin object descriptor",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
Plugins::IAlgorithmDesc* pluginObjectDescT = dynamic_cast<Plugins::IAlgorithmDesc*>(desc);
|
||||
Plugins::IAlgorithm* pluginObjectT = dynamic_cast<Plugins::IAlgorithm*>(pluginObject);
|
||||
|
||||
OV_ERROR_UNLESS_KRN(pluginObjectDescT && pluginObjectT,
|
||||
"Could not downcast plugin object and/or plugin object descriptor for " << algorithmDesc.getName() << " plugin object descriptor",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_pluginObjects[pluginObjectDescT].push_back(pluginObjectT);
|
||||
}
|
||||
|
||||
return pluginObjectT;
|
||||
}
|
||||
|
||||
Plugins::IBoxAlgorithm* CPluginManager::createBoxAlgorithm(const CIdentifier& classID, const Plugins::IBoxAlgorithmDesc** boxAlgorithmDesc)
|
||||
{
|
||||
return createPluginObjectT<Plugins::IBoxAlgorithm, Plugins::IBoxAlgorithmDesc>(classID, boxAlgorithmDesc);
|
||||
}
|
||||
|
||||
template <class IPluginObjectT, class IPluginObjectDescT>
|
||||
IPluginObjectT* CPluginManager::createPluginObjectT(const CIdentifier& classID, const IPluginObjectDescT** ppPluginObjectDescT)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
if (ppPluginObjectDescT) { *ppPluginObjectDescT = nullptr; }
|
||||
|
||||
CIdentifier substitutionTokenID;
|
||||
char substitutionTokenName[1024];
|
||||
const uint64_t srcClassID = classID.id();
|
||||
uint64_t dstClassID = srcClassID;
|
||||
sprintf(substitutionTokenName, "Kernel_PluginSubstitution_%0" PRIx64, srcClassID);
|
||||
if ((substitutionTokenID = this->getConfigurationManager().lookUpConfigurationTokenIdentifier(substitutionTokenName)) !=
|
||||
CIdentifier::undefined())
|
||||
{
|
||||
CString value = this->getConfigurationManager().getConfigurationTokenValue(substitutionTokenID);
|
||||
value = this->getConfigurationManager().expand(value);
|
||||
|
||||
try { dstClassID = std::stoull(value.toASCIIString(), nullptr, 16); }
|
||||
catch (const std::invalid_argument& exception)
|
||||
{
|
||||
OV_ERROR_KRN("Received exception while converting class identifier from string to number: " << exception.what(), Kernel::ErrorType::BadArgument);
|
||||
}
|
||||
catch (const std::out_of_range& exception)
|
||||
{
|
||||
OV_ERROR_KRN("Received exception while converting class identifier from string to number: " << exception.what(), Kernel::ErrorType::OutOfBound);
|
||||
}
|
||||
}
|
||||
if (dstClassID != srcClassID)
|
||||
{
|
||||
this->getLogManager() << LogLevel_Trace << "Substituting plugin class identifier " << CIdentifier(srcClassID) <<
|
||||
" with new class identifier " << CIdentifier(dstClassID) << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
this->getLogManager() << LogLevel_Debug << "Not substitute plugin found for class identifier " << CIdentifier(srcClassID) <<
|
||||
" (configuration token name was " << CString(substitutionTokenName) << ")\n";
|
||||
}
|
||||
|
||||
Plugins::IPluginObjectDesc* pod = nullptr;
|
||||
for (auto i = m_pluginObjectDescs.begin(); i != m_pluginObjectDescs.end(); ++i)
|
||||
{
|
||||
if (i->first->getCreatedClass() == CIdentifier(dstClassID)) { pod = i->first; }
|
||||
}
|
||||
|
||||
OV_ERROR_UNLESS_KRN(pod,
|
||||
"Did not find the plugin object descriptor with requested class identifier " << CIdentifier(srcClassID).str() <<
|
||||
" in registered plugin object descriptors",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
Plugins::IPluginObject* pluginObject = pod->create();
|
||||
|
||||
OV_ERROR_UNLESS_KRN(pluginObject,
|
||||
"Could not create plugin object from " << pod->getName() << " plugin object descriptor",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
IPluginObjectDescT* pluginObjectDescT = dynamic_cast<IPluginObjectDescT*>(pod);
|
||||
IPluginObjectT* pluginObjectT = dynamic_cast<IPluginObjectT*>(pluginObject);
|
||||
|
||||
OV_ERROR_UNLESS_KRN(pluginObjectDescT && pluginObjectT,
|
||||
"Could not downcast plugin object and/or plugin object descriptor for " << pod->getName() << " plugin object descriptor",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
if (ppPluginObjectDescT) { *ppPluginObjectDescT = pluginObjectDescT; }
|
||||
|
||||
m_pluginObjects[pluginObjectDescT].push_back(pluginObjectT);
|
||||
|
||||
return pluginObjectT;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CPluginManager final : public TKernelObject<IPluginManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPluginManager(const IKernelContext& ctx) : TKernelObject<IPluginManager>(ctx) {}
|
||||
~CPluginManager() override;
|
||||
bool addPluginsFromFiles(const CString& rFileNameWildCard) override;
|
||||
bool registerPluginDesc(const Plugins::IPluginObjectDesc& rPluginObjectDesc) override;
|
||||
CIdentifier getNextPluginObjectDescIdentifier(const CIdentifier& previousID) const override;
|
||||
CIdentifier getNextPluginObjectDescIdentifier(const CIdentifier& previousID, const CIdentifier& baseClassID) const override;
|
||||
bool canCreatePluginObject(const CIdentifier& classID) override;
|
||||
const Plugins::IPluginObjectDesc* getPluginObjectDesc(const CIdentifier& classID) const override;
|
||||
const Plugins::IPluginObjectDesc* getPluginObjectDescCreating(const CIdentifier& classID) const override;
|
||||
CIdentifier getPluginObjectHashValue(const CIdentifier& classID) const override;
|
||||
CIdentifier getPluginObjectHashValue(const Plugins::IBoxAlgorithmDesc& boxAlgorithmDesc) const override;
|
||||
bool isPluginObjectFlaggedAsDeprecated(const CIdentifier& classID) const override;
|
||||
Plugins::IPluginObject* createPluginObject(const CIdentifier& classID) override;
|
||||
bool releasePluginObject(Plugins::IPluginObject* pluginObject) override;
|
||||
Plugins::IAlgorithm* createAlgorithm(const CIdentifier& classID, const Plugins::IAlgorithmDesc** algorithmDesc) override;
|
||||
Plugins::IAlgorithm* createAlgorithm(const Plugins::IAlgorithmDesc& algorithmDesc) override;
|
||||
Plugins::IBoxAlgorithm* createBoxAlgorithm(const CIdentifier& classID, const Plugins::IBoxAlgorithmDesc** boxAlgorithmDesc) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPluginManager>, OVK_ClassId_Kernel_Plugins_PluginManager)
|
||||
|
||||
protected:
|
||||
|
||||
template <class TPluginObject, class TPluginObjectDesc>
|
||||
TPluginObject* createPluginObjectT(const CIdentifier& classID, const TPluginObjectDesc** ppPluginObjectDescT);
|
||||
|
||||
std::vector<IPluginModule*> m_pluginModules;
|
||||
std::map<Plugins::IPluginObjectDesc*, IPluginModule*> m_pluginObjectDescs;
|
||||
std::map<Plugins::IPluginObjectDesc*, std::vector<Plugins::IPluginObject*>> m_pluginObjects;
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
#include "ovkCPluginModule.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
#include <dlfcn.h>
|
||||
#elif defined TARGET_OS_Windows
|
||||
#include <windows.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CPluginModuleBase : public TKernelObject<IPluginModule>
|
||||
{
|
||||
public:
|
||||
explicit CPluginModuleBase(const IKernelContext& ctx)
|
||||
: TKernelObject<IPluginModule>(ctx), m_onInitializeCB(nullptr), m_onGetPluginObjectDescCB(nullptr), m_onUninitializeCB(nullptr) {}
|
||||
|
||||
~CPluginModuleBase() override { }
|
||||
bool initialize() override;
|
||||
bool getPluginObjectDescription(size_t index, Plugins::IPluginObjectDesc*& pluginObjectDesc) override;
|
||||
bool uninitialize() override;
|
||||
bool getFileName(CString& fileName) const override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPluginModule>, CIdentifier::undefined())
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool isOpen() const = 0;
|
||||
|
||||
std::vector<Plugins::IPluginObjectDesc*> m_pluginObjectDescs;
|
||||
CString m_filename;
|
||||
bool m_gotDesc = false;
|
||||
|
||||
bool (*m_onInitializeCB)(const IPluginModuleContext&);
|
||||
bool (*m_onGetPluginObjectDescCB)(const IPluginModuleContext&, size_t, Plugins::IPluginObjectDesc*&);
|
||||
bool (*m_onUninitializeCB)(const IPluginModuleContext&);
|
||||
};
|
||||
|
||||
namespace {
|
||||
class CPluginModuleContext final : public TKernelObject<IPluginModuleContext>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPluginModuleContext(const IKernelContext& ctx)
|
||||
: TKernelObject<IPluginModuleContext>(ctx), m_logManager(ctx.getLogManager()), m_typeManager(ctx.getTypeManager()),
|
||||
m_scenarioManager(ctx.getScenarioManager()) { }
|
||||
|
||||
ILogManager& getLogManager() const override { return m_logManager; }
|
||||
ITypeManager& getTypeManager() const override { return m_typeManager; }
|
||||
IScenarioManager& getScenarioManager() const override { return m_scenarioManager; }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPluginModuleContext>, OVK_ClassId_Kernel_Plugins_PluginModuleContext)
|
||||
|
||||
protected:
|
||||
|
||||
ILogManager& m_logManager;
|
||||
ITypeManager& m_typeManager;
|
||||
IScenarioManager& m_scenarioManager;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool CPluginModuleBase::initialize()
|
||||
{
|
||||
if (!isOpen()) { return false; }
|
||||
if (!m_onInitializeCB) { return true; }
|
||||
return m_onInitializeCB(CPluginModuleContext(getKernelContext()));
|
||||
}
|
||||
|
||||
bool CPluginModuleBase::getPluginObjectDescription(const size_t index, Plugins::IPluginObjectDesc*& pluginObjectDesc)
|
||||
{
|
||||
if (!m_gotDesc)
|
||||
{
|
||||
if (!isOpen() || !m_onGetPluginObjectDescCB) { return false; }
|
||||
|
||||
size_t idx = 0;
|
||||
Plugins::IPluginObjectDesc* pod = nullptr;
|
||||
while (m_onGetPluginObjectDescCB(CPluginModuleContext(getKernelContext()), idx, pod))
|
||||
{
|
||||
if (pod) { m_pluginObjectDescs.push_back(pod); }
|
||||
idx++;
|
||||
}
|
||||
|
||||
m_gotDesc = true;
|
||||
}
|
||||
|
||||
if (index >= m_pluginObjectDescs.size())
|
||||
{
|
||||
pluginObjectDesc = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
pluginObjectDesc = m_pluginObjectDescs[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginModuleBase::uninitialize()
|
||||
{
|
||||
if (!isOpen()) { return false; }
|
||||
if (!m_onUninitializeCB) { return true; }
|
||||
return m_onUninitializeCB(CPluginModuleContext(getKernelContext()));
|
||||
}
|
||||
|
||||
bool CPluginModuleBase::getFileName(CString& fileName) const
|
||||
{
|
||||
if (!isOpen()) { return false; }
|
||||
fileName = m_filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
class CPluginModuleLinux : public CPluginModuleBase
|
||||
{
|
||||
public:
|
||||
|
||||
CPluginModuleLinux(const IKernelContext& ctx);
|
||||
|
||||
virtual bool load(const CString& filename, CString* pError);
|
||||
virtual bool unload(CString* pError);
|
||||
virtual bool isOpen() const;
|
||||
|
||||
protected:
|
||||
|
||||
void* m_fileHandle;
|
||||
};
|
||||
|
||||
#elif defined TARGET_OS_Windows
|
||||
class CPluginModuleWindows final : public CPluginModuleBase
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPluginModuleWindows(const IKernelContext& ctx);
|
||||
bool load(const CString& filename, CString* pError) override;
|
||||
bool unload(CString* pError) override;
|
||||
|
||||
protected:
|
||||
bool isOpen() const override { return m_fileHandle != nullptr; }
|
||||
|
||||
HMODULE m_fileHandle;
|
||||
|
||||
private:
|
||||
|
||||
static CString getLastErrorMessageString();
|
||||
};
|
||||
|
||||
#else
|
||||
class CPluginModuleDummy : public CPluginModuleBase
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPluginModuleDummy(const IKernelContext& ctx);
|
||||
|
||||
virtual bool load(const CString& filename, CString* pError);
|
||||
virtual bool unload(CString* pError);
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool isOpen() const;
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
|
||||
CPluginModuleLinux::CPluginModuleLinux(const IKernelContext& ctx) :CPluginModuleBase(ctx),m_fileHandle(NULL) { }
|
||||
|
||||
bool CPluginModuleLinux::load(const CString& filename, CString* pError)
|
||||
{
|
||||
if(m_fileHandle)
|
||||
{
|
||||
if(pError) *pError="plugin module already loaded";
|
||||
return false;
|
||||
}
|
||||
|
||||
// m_fileHandle=dlopen(filename, RTLD_NOW|RTLD_LOCAL);
|
||||
#if defined OV_LOCAL_SYMBOLS
|
||||
m_fileHandle = dlopen(filename, RTLD_LAZY|RTLD_LOCAL);
|
||||
#else
|
||||
m_fileHandle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
|
||||
#endif
|
||||
if(!m_fileHandle)
|
||||
{
|
||||
if(pError) *pError=dlerror();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_onInitializeCB=(bool (*)(const IPluginModuleContext&))dlsym(m_fileHandle, "onInitialize");
|
||||
m_onUninitializeCB=(bool (*)(const IPluginModuleContext&))dlsym(m_fileHandle, "onUninitialize");
|
||||
m_onGetPluginObjectDescCB=(bool (*)(const IPluginModuleContext&, size_t, Plugins::IPluginObjectDesc*&))dlsym(m_fileHandle, "onGetPluginObjectDescription");
|
||||
|
||||
if(!m_onGetPluginObjectDescCB)
|
||||
{
|
||||
if(pError) *pError=dlerror();
|
||||
|
||||
dlclose(m_fileHandle);
|
||||
m_fileHandle=NULL;
|
||||
m_onInitializeCB=NULL;
|
||||
m_onUninitializeCB=NULL;
|
||||
m_onGetPluginObjectDescCB=NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_filename=filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginModuleLinux::unload(CString* error)
|
||||
{
|
||||
if(!m_fileHandle)
|
||||
{
|
||||
if (error) { *error = "no plugin module currently loaded"; }
|
||||
return false;
|
||||
}
|
||||
|
||||
dlclose(m_fileHandle);
|
||||
m_fileHandle = NULL;
|
||||
m_onInitializeCB = NULL;
|
||||
m_onUninitializeCB = NULL;
|
||||
m_onGetPluginObjectDescCB = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginModuleLinux::isOpen() const { return m_fileHandle != nullptr; }
|
||||
|
||||
#elif defined TARGET_OS_Windows
|
||||
|
||||
CPluginModuleWindows::CPluginModuleWindows(const IKernelContext& ctx) : CPluginModuleBase(ctx), m_fileHandle(nullptr) {}
|
||||
|
||||
bool CPluginModuleWindows::load(const CString& filename, CString* pError)
|
||||
{
|
||||
if (m_fileHandle)
|
||||
{
|
||||
if (pError) { *pError = "plugin module already loaded"; }
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fileHandle = LoadLibrary(filename);
|
||||
if (!m_fileHandle)
|
||||
{
|
||||
if (pError) { *pError = this->getLastErrorMessageString(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
m_onInitializeCB = reinterpret_cast<bool (*)(const IPluginModuleContext&)>(GetProcAddress(m_fileHandle, "onInitialize"));
|
||||
m_onUninitializeCB = reinterpret_cast<bool (*)(const IPluginModuleContext&)>(GetProcAddress(m_fileHandle, "onUninitialize"));
|
||||
m_onGetPluginObjectDescCB = reinterpret_cast<bool (*)(const IPluginModuleContext&, size_t, Plugins::IPluginObjectDesc*&)>(GetProcAddress(
|
||||
m_fileHandle, "onGetPluginObjectDescription"));
|
||||
if (!m_onGetPluginObjectDescCB)
|
||||
{
|
||||
if (pError) { *pError = this->getLastErrorMessageString(); }
|
||||
|
||||
FreeLibrary(m_fileHandle);
|
||||
m_fileHandle = nullptr;
|
||||
m_onInitializeCB = nullptr;
|
||||
m_onGetPluginObjectDescCB = nullptr;
|
||||
m_onUninitializeCB = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_filename = filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginModuleWindows::unload(CString* pError)
|
||||
{
|
||||
if (!m_fileHandle)
|
||||
{
|
||||
if (pError) { *pError = "no plugin module currently loaded"; }
|
||||
return false;
|
||||
}
|
||||
|
||||
FreeLibrary(m_fileHandle);
|
||||
m_fileHandle = nullptr;
|
||||
m_onInitializeCB = nullptr;
|
||||
m_onGetPluginObjectDescCB = nullptr;
|
||||
m_onUninitializeCB = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
CString CPluginModuleWindows::getLastErrorMessageString()
|
||||
{
|
||||
CString res;
|
||||
|
||||
char* buffer = nullptr;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), 0,
|
||||
reinterpret_cast<LPTSTR>(&buffer), 0, nullptr);
|
||||
if (buffer)
|
||||
{
|
||||
const size_t length = strlen(buffer);
|
||||
for (size_t i = 0; i < length; ++i) { if (buffer[i] == '\n' || buffer[i] == '\r') { buffer[i] = ' '; } }
|
||||
res = buffer;
|
||||
}
|
||||
LocalFree(LPVOID(buffer));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
CPluginModule::CPluginModule(const IKernelContext& ctx)
|
||||
: TKernelObject<IPluginModule>(ctx)
|
||||
{
|
||||
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
m_impl=new CPluginModuleLinux(getKernelContext());
|
||||
#elif defined TARGET_OS_Windows
|
||||
m_impl = new CPluginModuleWindows(getKernelContext());
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
CPluginModule::~CPluginModule() { delete m_impl; }
|
||||
|
||||
bool CPluginModule::load(const CString& filename, CString* error) { return !m_impl ? false : m_impl->load(filename, error); }
|
||||
bool CPluginModule::unload(CString* error) { return !m_impl ? false : m_impl->unload(error); }
|
||||
bool CPluginModule::initialize() { return !m_impl ? false : m_impl->initialize(); }
|
||||
|
||||
bool CPluginModule::getPluginObjectDescription(const size_t index, Plugins::IPluginObjectDesc*& desc)
|
||||
{
|
||||
return !m_impl ? false : m_impl->getPluginObjectDescription(index, desc);
|
||||
}
|
||||
|
||||
bool CPluginModule::uninitialize() { return !m_impl ? false : m_impl->uninitialize(); }
|
||||
bool CPluginModule::getFileName(CString& rFileName) const { return !m_impl ? false : m_impl->getFileName(rFileName); }
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CPluginModule final : public TKernelObject<IPluginModule>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPluginModule(const IKernelContext& ctx);
|
||||
~CPluginModule() override;
|
||||
bool load(const CString& filename, CString* error) override;
|
||||
bool unload(CString* error) override;
|
||||
bool getFileName(CString& rFileName) const override;
|
||||
bool initialize() override;
|
||||
bool getPluginObjectDescription(size_t index, Plugins::IPluginObjectDesc*& desc) override;
|
||||
bool uninitialize() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IPluginModule>, OVK_ClassId_Kernel_Plugins_PluginModule)
|
||||
|
||||
protected:
|
||||
|
||||
IPluginModule* m_impl = nullptr;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CBoxListenerContext final : public TKernelObject<IBoxListenerContext>
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxListenerContext(const IKernelContext& ctx, IBox& box, const size_t index)
|
||||
: TKernelObject<IBoxListenerContext>(ctx), m_box(box), m_idx(index) { }
|
||||
|
||||
IAlgorithmManager& getAlgorithmManager() const override { return this->getKernelContext().getAlgorithmManager(); }
|
||||
IPlayerManager& getPlayerManager() const override { return this->getKernelContext().getPlayerManager(); }
|
||||
IPluginManager& getPluginManager() const override { return this->getKernelContext().getPluginManager(); }
|
||||
IMetaboxManager& getMetaboxManager() const override { return this->getKernelContext().getMetaboxManager(); }
|
||||
IScenarioManager& getScenarioManager() const override { return this->getKernelContext().getScenarioManager(); }
|
||||
ITypeManager& getTypeManager() const override { return this->getKernelContext().getTypeManager(); }
|
||||
ILogManager& getLogManager() const override { return this->getKernelContext().getLogManager(); }
|
||||
IErrorManager& getErrorManager() const override { return this->getKernelContext().getErrorManager(); }
|
||||
IConfigurationManager& getConfigurationManager() const override { return this->getKernelContext().getConfigurationManager(); }
|
||||
IBox& getBox() const override { return m_box; }
|
||||
|
||||
IScenario& getScenario() const override
|
||||
{
|
||||
OV_FATAL("Getting scenario from box listener context is not yet implemented", Kernel::ErrorType::NotImplemented, this->getKernelContext().getLogManager());
|
||||
}
|
||||
|
||||
size_t getIndex() const override { return m_idx; }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IBoxListenerContext>, OVK_ClassId_Kernel_Scenario_BoxListenerContext)
|
||||
|
||||
private:
|
||||
|
||||
IBox& m_box;
|
||||
size_t m_idx = 0;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
#include "ovkCBoxProto.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
bool CBoxProto::addInput(const CString& name, const CIdentifier& typeID, const CIdentifier& id, const bool notify)
|
||||
{
|
||||
if (!m_box.addInput(name, typeID, id, notify)) { return false; }
|
||||
|
||||
const std::string tmp = std::to_string(m_box.getInputCount());
|
||||
const CString buffer(tmp.c_str());
|
||||
if (m_box.hasAttribute(OV_AttributeId_Box_InitialInputCount)) { m_box.setAttributeValue(OV_AttributeId_Box_InitialInputCount, buffer); }
|
||||
else { m_box.addAttribute(OV_AttributeId_Box_InitialInputCount, buffer); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxProto::addOutput(const CString& name, const CIdentifier& typeID, const CIdentifier& id, const bool notify)
|
||||
{
|
||||
if (!m_box.addOutput(name, typeID, id, notify)) { return false; }
|
||||
|
||||
const std::string tmp = std::to_string(m_box.getOutputCount());
|
||||
const CString buffer(tmp.c_str());
|
||||
if (m_box.hasAttribute(OV_AttributeId_Box_InitialOutputCount)) { m_box.setAttributeValue(OV_AttributeId_Box_InitialOutputCount, buffer); }
|
||||
else { m_box.addAttribute(OV_AttributeId_Box_InitialOutputCount, buffer); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxProto::addSetting(const CString& name, const CIdentifier& typeID, const CString& value, const bool modifiable,
|
||||
const CIdentifier& id, const bool notify)
|
||||
{
|
||||
if (!m_box.addSetting(name, typeID, value, size_t(-1), modifiable, id, notify)) { return false; }
|
||||
|
||||
const std::string tmp = std::to_string(m_box.getSettingCount());
|
||||
const CString buffer(tmp.c_str());
|
||||
if (m_box.hasAttribute(OV_AttributeId_Box_InitialSettingCount)) { m_box.setAttributeValue(OV_AttributeId_Box_InitialSettingCount, buffer); }
|
||||
else { m_box.addAttribute(OV_AttributeId_Box_InitialSettingCount, buffer); }
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
size_t CBoxProto::addSetting(const CString& name, const CIdentifier& typeID, const CString& sDefaultValue, const bool bModifiable)
|
||||
{
|
||||
addSetting(name, typeID, sDefaultValue);
|
||||
size_t lastSetting = m_box.getSettingCount();
|
||||
m_box.setSettingMod(lastSetting, bModifiable);
|
||||
return true;
|
||||
}
|
||||
/*/
|
||||
|
||||
bool CBoxProto::addFlag(const EBoxFlag boxFlag)
|
||||
{
|
||||
switch (boxFlag)
|
||||
{
|
||||
case BoxFlag_CanAddInput: m_box.addAttribute(OV_AttributeId_Box_FlagCanAddInput, "");
|
||||
break;
|
||||
case BoxFlag_CanModifyInput: m_box.addAttribute(OV_AttributeId_Box_FlagCanModifyInput, "");
|
||||
break;
|
||||
case BoxFlag_CanAddOutput: m_box.addAttribute(OV_AttributeId_Box_FlagCanAddOutput, "");
|
||||
break;
|
||||
case BoxFlag_CanModifyOutput: m_box.addAttribute(OV_AttributeId_Box_FlagCanModifyOutput, "");
|
||||
break;
|
||||
case BoxFlag_CanAddSetting: m_box.addAttribute(OV_AttributeId_Box_FlagCanAddSetting, "");
|
||||
break;
|
||||
case BoxFlag_CanModifySetting: m_box.addAttribute(OV_AttributeId_Box_FlagCanModifySetting, "");
|
||||
break;
|
||||
case BoxFlag_ManualUpdate: m_box.addAttribute(OV_AttributeId_Box_FlagNeedsManualUpdate, "");
|
||||
break;
|
||||
case BoxFlag_IsDeprecated: break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxProto::addFlag(const CIdentifier& flagID)
|
||||
{
|
||||
const uint64_t value = getKernelContext().getTypeManager().getEnumerationEntryValueFromName(OV_TypeId_BoxAlgorithmFlag, flagID.toString());
|
||||
if (value == CIdentifier::undefined().id()) { return false; }
|
||||
m_box.addAttribute(flagID, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CBoxProto : public TKernelObject<IBoxProto>
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxProto(const IKernelContext& ctx, IBox& box) : TKernelObject<IBoxProto>(ctx), m_box(box) {}
|
||||
~CBoxProto() override = default;
|
||||
bool addInput(const CString& name, const CIdentifier& typeID, const CIdentifier& id = CIdentifier::undefined(), const bool notify = true) override;
|
||||
bool addOutput(const CString& name, const CIdentifier& typeID, const CIdentifier& id = CIdentifier::undefined(), const bool notify = true) override;
|
||||
|
||||
//virtual bool addSetting(const CString& name, const CIdentifier& typeID, const CString& value);
|
||||
bool addSetting(const CString& name, const CIdentifier& typeID, const CString& value,
|
||||
const bool modifiable = false, const CIdentifier& id = CIdentifier::undefined(), const bool notify = true) override;
|
||||
bool addFlag(const EBoxFlag boxFlag) override;
|
||||
bool addFlag(const CIdentifier& flagID) override;
|
||||
bool addInputSupport(const CIdentifier& typeID) override { return m_box.addInputSupport(typeID); }
|
||||
bool addOutputSupport(const CIdentifier& typeID) override { return m_box.addOutputSupport(typeID); }
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IBoxProto>, OVK_ClassId_Kernel_Scenario_BoxProto)
|
||||
|
||||
protected:
|
||||
|
||||
IBox& m_box;
|
||||
|
||||
private:
|
||||
|
||||
CBoxProto() = delete;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,296 @@
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include "ovkCScenario.h"
|
||||
#include "ovkCBoxUpdater.h"
|
||||
#include "ovkTBox.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
const std::array<CIdentifier, 10> CBoxUpdater::UPDATABLE_ATTRIBUTES = {
|
||||
OV_AttributeId_Box_InitialPrototypeHashValue,
|
||||
OV_AttributeId_Box_InitialInputCount,
|
||||
OV_AttributeId_Box_InitialOutputCount,
|
||||
OV_AttributeId_Box_InitialSettingCount,
|
||||
OV_AttributeId_Box_FlagCanAddInput,
|
||||
OV_AttributeId_Box_FlagCanModifyInput,
|
||||
OV_AttributeId_Box_FlagCanAddOutput,
|
||||
OV_AttributeId_Box_FlagCanModifyOutput,
|
||||
OV_AttributeId_Box_FlagCanAddSetting,
|
||||
OV_AttributeId_Box_FlagCanModifySetting
|
||||
};
|
||||
|
||||
CBoxUpdater::CBoxUpdater(CScenario& scenario, IBox* box)
|
||||
: TKernelObject<IKernelObject>(scenario.getKernelContext()), m_scenario(&scenario), m_sourceBox(box)
|
||||
{
|
||||
m_originalToUpdatedCorrespondence[Input] = std::map<size_t, size_t>();
|
||||
m_originalToUpdatedCorrespondence[Output] = std::map<size_t, size_t>();
|
||||
m_originalToUpdatedCorrespondence[Setting] = std::map<size_t, size_t>();
|
||||
}
|
||||
|
||||
CBoxUpdater::~CBoxUpdater()
|
||||
{
|
||||
if (!m_kernelBox || !m_updatedBox) { return; }
|
||||
|
||||
if (m_kernelBox->getAlgorithmClassIdentifier() != OVP_ClassId_BoxAlgorithm_Metabox)
|
||||
{
|
||||
// do not manage destruction of metaboxes (done by metabox manager)
|
||||
delete m_kernelBox;
|
||||
}
|
||||
|
||||
delete m_updatedBox;
|
||||
}
|
||||
|
||||
bool CBoxUpdater::initialize()
|
||||
{
|
||||
// initialize kernel box reference
|
||||
if (m_sourceBox->getAlgorithmClassIdentifier() == OVP_ClassId_BoxAlgorithm_Metabox)
|
||||
{
|
||||
const CString metaboxID = m_sourceBox->getAttributeValue(OVP_AttributeId_Metabox_ID);
|
||||
OV_ERROR_UNLESS_KRF(metaboxID != CString(""), "Failed to find metabox with id " << metaboxID, Kernel::ErrorType::BadCall);
|
||||
|
||||
CIdentifier metaboxId;
|
||||
metaboxId.fromString(metaboxID);
|
||||
const CString path(this->getKernelContext().getMetaboxManager().getMetaboxFilePath(metaboxId));
|
||||
|
||||
OV_ERROR_UNLESS_KRF(path != CString(""), "Metabox scenario is not available for " << m_sourceBox->getName(), Kernel::ErrorType::BadCall);
|
||||
|
||||
|
||||
// We are going to copy the template scenario, flatten it and then copy all
|
||||
// Note that copy constructor for IScenario does not exist
|
||||
CIdentifier templateID;
|
||||
this->getKernelContext().getScenarioManager().importScenarioFromFile(templateID, OV_ScenarioImportContext_SchedulerMetaboxImport, path);
|
||||
|
||||
CScenario* instance = dynamic_cast<CScenario*>(&(this->getKernelContext().getScenarioManager().getScenario(templateID)));
|
||||
instance->setAlgorithmClassIdentifier(OVP_ClassId_BoxAlgorithm_Metabox);
|
||||
m_kernelBox = instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
CBox* kernelBox = new CBox(m_scenario->getKernelContext());
|
||||
kernelBox->initializeFromAlgorithmClassIdentifierNoInit(m_sourceBox->getAlgorithmClassIdentifier());
|
||||
m_kernelBox = kernelBox;
|
||||
}
|
||||
|
||||
// initialize updated box
|
||||
m_updatedBox = new CBox(m_scenario->getKernelContext());
|
||||
|
||||
m_updatedBox->setIdentifier(m_sourceBox->getIdentifier());
|
||||
m_updatedBox->setName(m_sourceBox->getName());
|
||||
|
||||
if (m_sourceBox->getAlgorithmClassIdentifier() == OVP_ClassId_BoxAlgorithm_Metabox)
|
||||
{
|
||||
m_updatedBox->setAttributeValue(OV_AttributeId_Box_InitialPrototypeHashValue, m_kernelBox->getAttributeValue(OV_AttributeId_Scenario_MetaboxHash));
|
||||
}
|
||||
|
||||
// initialize updated box attribute to kernel ones
|
||||
CIdentifier attributeIdentifier;
|
||||
while ((attributeIdentifier = m_kernelBox->getNextAttributeIdentifier(attributeIdentifier)) != CIdentifier::undefined())
|
||||
{
|
||||
CString attributeValue = m_kernelBox->getAttributeValue(attributeIdentifier);
|
||||
m_updatedBox->addAttribute(attributeIdentifier, attributeValue);
|
||||
}
|
||||
|
||||
// initialize supported types to kernel ones
|
||||
if (m_sourceBox->getAlgorithmClassIdentifier() != OVP_ClassId_BoxAlgorithm_Metabox)
|
||||
{
|
||||
m_updatedBox->setSupportTypeFromAlgorithmIdentifier(m_kernelBox->getAlgorithmClassIdentifier());
|
||||
}
|
||||
// should not be done before adding IO elements so the box listener is never called
|
||||
// updatedBox->setAlgorithmClassIdentifier(kernelBox->getAlgorithmClassIdentifier());
|
||||
m_initialized = true;
|
||||
|
||||
m_isUpdateRequired = false;
|
||||
|
||||
const bool isHashDifferent = m_scenario->isBoxOutdated(m_sourceBox->getIdentifier());
|
||||
|
||||
if (this->flaggedForManualUpdate())
|
||||
{
|
||||
m_isUpdateRequired = isHashDifferent;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isHashDifferent)
|
||||
{
|
||||
m_isUpdateRequired |= this->updateInterfacors(Input);
|
||||
m_isUpdateRequired |= this->updateInterfacors(Output);
|
||||
m_isUpdateRequired |= this->updateInterfacors(Setting);
|
||||
m_isUpdateRequired |= this->checkForSupportedTypesToBeUpdated();
|
||||
m_isUpdateRequired |= this->checkForSupportedIOSAttributesToBeUpdated();
|
||||
}
|
||||
|
||||
if (m_sourceBox->getAlgorithmClassIdentifier() == OVP_ClassId_BoxAlgorithm_Metabox) { m_isUpdateRequired |= isHashDifferent; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBoxUpdater::checkForSupportedTypesToBeUpdated() const
|
||||
{
|
||||
//check for supported inputs diff
|
||||
for (auto& type : m_sourceBox->getInputSupportTypes()) { if (!m_kernelBox->hasInputSupport(type)) { return true; } }
|
||||
for (auto& type : m_kernelBox->getInputSupportTypes()) { if (!m_sourceBox->hasInputSupport(type)) { return true; } }
|
||||
|
||||
//check for supported outputs diff
|
||||
for (auto& type : m_sourceBox->getOutputSupportTypes()) { if (!m_kernelBox->hasOutputSupport(type)) { return true; } }
|
||||
for (auto& type : m_kernelBox->getOutputSupportTypes()) { if (!m_sourceBox->hasOutputSupport(type)) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBoxUpdater::checkForSupportedIOSAttributesToBeUpdated() const
|
||||
{
|
||||
// check for attributes
|
||||
for (auto& attr : UPDATABLE_ATTRIBUTES)
|
||||
{
|
||||
if ((m_sourceBox->hasAttribute(attr) && !m_kernelBox->hasAttribute(attr))
|
||||
|| (!m_sourceBox->hasAttribute(attr) && m_kernelBox->hasAttribute(attr))) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBoxUpdater::updateInterfacors(const EBoxInterfacorType interfacorType)
|
||||
{
|
||||
std::vector<InterfacorRequest> interfacors;
|
||||
|
||||
bool updated = false;
|
||||
|
||||
// First add and optionally modify all requests from the Kernel prototype
|
||||
size_t index = 0;
|
||||
while (index < m_kernelBox->getInterfacorCount(interfacorType))
|
||||
{
|
||||
CIdentifier kTypeIdentifier;
|
||||
CIdentifier kIdentifier;
|
||||
CString kName;
|
||||
m_kernelBox->getInterfacorType(interfacorType, index, kTypeIdentifier);
|
||||
m_kernelBox->getInterfacorIdentifier(interfacorType, index, kIdentifier);
|
||||
m_kernelBox->getInterfacorName(interfacorType, index, kName);
|
||||
|
||||
|
||||
InterfacorRequest request;
|
||||
request.index = index;
|
||||
request.identifier = kIdentifier;
|
||||
request.name = kName;
|
||||
request.typeID = kTypeIdentifier;
|
||||
request.toBeRemoved = false;
|
||||
|
||||
if (interfacorType == Setting)
|
||||
{
|
||||
CString defaultValue;
|
||||
bool modifiable;
|
||||
m_kernelBox->getSettingDefaultValue(index, defaultValue);
|
||||
m_kernelBox->getSettingMod(index, modifiable);
|
||||
request.defaultValue = defaultValue;
|
||||
request.value = defaultValue;
|
||||
request.modifiability = modifiable;
|
||||
}
|
||||
|
||||
auto indexInBox = getInterfacorIndex(interfacorType, *m_sourceBox, kTypeIdentifier, kIdentifier, kName);
|
||||
if (indexInBox != size_t(-1))
|
||||
{
|
||||
CIdentifier identifier;
|
||||
CString name;
|
||||
|
||||
m_sourceBox->getInterfacorIdentifier(interfacorType, indexInBox, identifier);
|
||||
m_sourceBox->getInterfacorName(interfacorType, indexInBox, name);
|
||||
updated |= (identifier == kIdentifier && name != kName) || (identifier != kIdentifier && name == kName);
|
||||
|
||||
m_originalToUpdatedCorrespondence[interfacorType][indexInBox] = index;
|
||||
|
||||
// For settings, we need to give them the value from the original box
|
||||
if (interfacorType == Setting)
|
||||
{
|
||||
CString valueInBox;
|
||||
m_sourceBox->getSettingValue(indexInBox, valueInBox);
|
||||
request.value = valueInBox;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to modify the type in the kernel proto to adjust to the inputs
|
||||
updated = true;
|
||||
}
|
||||
|
||||
interfacors.push_back(request);
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
// Now go throught the inputs we have not yet associated and decide what to do with them
|
||||
// As we currently only support boxes with fixed amount of inputs/outputs this always means that the
|
||||
// I/O is redundant
|
||||
index = 0;
|
||||
while (index < m_sourceBox->getInterfacorCount(interfacorType))
|
||||
{
|
||||
// Skip if the input was handled in the previous step
|
||||
if (m_originalToUpdatedCorrespondence.at(interfacorType).find(index) != m_originalToUpdatedCorrespondence.at(interfacorType).end())
|
||||
{
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
|
||||
CIdentifier sTypeIdentifier;
|
||||
CIdentifier sIdentifier;
|
||||
CString name;
|
||||
m_sourceBox->getInterfacorType(interfacorType, index, sTypeIdentifier);
|
||||
m_sourceBox->getInterfacorIdentifier(interfacorType, index, sIdentifier);
|
||||
m_sourceBox->getInterfacorName(interfacorType, index, name);
|
||||
|
||||
InterfacorRequest request;
|
||||
request.index = index;
|
||||
request.identifier = sIdentifier;
|
||||
request.name = name;
|
||||
request.typeID = sTypeIdentifier;
|
||||
request.toBeRemoved = true;
|
||||
|
||||
if (interfacorType == Setting)
|
||||
{
|
||||
CString defaultValue;
|
||||
CString value;
|
||||
bool modifiable;
|
||||
m_sourceBox->getSettingDefaultValue(index, defaultValue);
|
||||
m_sourceBox->getSettingValue(index, value);
|
||||
m_sourceBox->getSettingMod(index, modifiable);
|
||||
request.defaultValue = defaultValue;
|
||||
request.value = value;
|
||||
request.modifiability = modifiable;
|
||||
}
|
||||
|
||||
updated = true;
|
||||
|
||||
interfacors.push_back(request);
|
||||
|
||||
m_originalToUpdatedCorrespondence[interfacorType][index] = interfacors.size() - 1;
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
for (auto& i : interfacors)
|
||||
{
|
||||
m_updatedBox->addInterfacor(interfacorType, i.name, i.typeID, i.identifier);
|
||||
if (interfacorType == Setting)
|
||||
{
|
||||
const auto idx = m_updatedBox->getInterfacorCountIncludingDeprecated(Setting) - 1;
|
||||
m_updatedBox->setSettingDefaultValue(idx, i.defaultValue);
|
||||
m_updatedBox->setSettingValue(idx, i.value);
|
||||
m_updatedBox->setSettingMod(idx, i.modifiability);
|
||||
}
|
||||
if (i.toBeRemoved)
|
||||
{
|
||||
m_updatedBox->setInterfacorDeprecatedStatus(interfacorType, m_updatedBox->getInterfacorCountIncludingDeprecated(interfacorType) - 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
size_t CBoxUpdater::getInterfacorIndex(const EBoxInterfacorType type, const IBox& box, const CIdentifier& typeID, const CIdentifier& id, const CString& name)
|
||||
{
|
||||
size_t index = size_t(-1);
|
||||
if (id != CIdentifier::undefined() && box.hasInterfacorWithIdentifier(type, id)) { box.getInterfacorIndex(type, id, index); }
|
||||
else if (box.hasInterfacorWithNameAndType(type, name, typeID)) { box.getInterfacorIndex(type, name, index); }
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include "ovkCScenario.h"
|
||||
|
||||
#include <map>
|
||||
#include <array>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
typedef struct _InterfacorRequest
|
||||
{
|
||||
size_t index = size_t(-1);
|
||||
CIdentifier identifier = CIdentifier::undefined();
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
CString name;
|
||||
bool toBeRemoved;
|
||||
|
||||
// only for settings
|
||||
CString defaultValue;
|
||||
bool modifiability = false;
|
||||
CString value;
|
||||
} InterfacorRequest;
|
||||
|
||||
class CBoxUpdater final : public TKernelObject<IKernelObject>
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxUpdater(CScenario& scenario, IBox* box);
|
||||
~CBoxUpdater() override;
|
||||
|
||||
bool initialize();
|
||||
|
||||
const std::map<size_t, size_t>& getOriginalToUpdatedInterfacorCorrespondence(const EBoxInterfacorType type) const
|
||||
{
|
||||
return m_originalToUpdatedCorrespondence.at(type);
|
||||
}
|
||||
|
||||
IBox& getUpdatedBox() const { return *m_updatedBox; }
|
||||
|
||||
bool flaggedForManualUpdate() const
|
||||
{
|
||||
OV_FATAL_UNLESS_K(m_initialized, "Box Updater is not initialized", Kernel::ErrorType::BadCall);
|
||||
|
||||
return m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagNeedsManualUpdate)
|
||||
|| m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagCanAddInput)
|
||||
|| m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagCanModifyInput)
|
||||
|| m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagCanAddOutput)
|
||||
|| m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagCanModifyOutput)
|
||||
|| m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagCanAddSetting)
|
||||
|| m_kernelBox->hasAttribute(OV_AttributeId_Box_FlagCanModifySetting);
|
||||
}
|
||||
|
||||
bool isUpdateRequired() const { return m_isUpdateRequired; }
|
||||
|
||||
static const std::array<CIdentifier, 10> UPDATABLE_ATTRIBUTES;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IKernelObject>, OV_ClassId_Kernel_Scenario_BoxUpdater)
|
||||
|
||||
private:
|
||||
|
||||
static size_t getInterfacorIndex(EBoxInterfacorType type, const IBox& box, const CIdentifier& typeID, const CIdentifier& id, const CString& name);
|
||||
bool updateInterfacors(EBoxInterfacorType interfacorType);
|
||||
|
||||
/**
|
||||
* \brief Check if supported type have to be updated between the box to be updated and the kernel
|
||||
* \return true when at least input or output supported types have to be updated
|
||||
*/
|
||||
bool checkForSupportedTypesToBeUpdated() const;
|
||||
|
||||
/**
|
||||
* \brief Check if supported inputs, outputs or settings attributes have to be updated between the box to be updated and the kernel
|
||||
* \return true when at least input, output or settings attributes have to be updated
|
||||
*/
|
||||
bool checkForSupportedIOSAttributesToBeUpdated() const;
|
||||
|
||||
// pointer to the parent scenario
|
||||
CScenario* m_scenario = nullptr;
|
||||
// pointer to the original box to be updated
|
||||
IBox* m_sourceBox = nullptr;
|
||||
// pointer to the kernel box
|
||||
const IBox* m_kernelBox = nullptr;
|
||||
// pointer to the updated box. This box will be used to update the prototype of the original box
|
||||
IBox* m_updatedBox = nullptr;
|
||||
// true when updater has been initialized
|
||||
bool m_initialized = false;
|
||||
|
||||
std::map<EBoxInterfacorType, std::map<size_t, size_t>> m_originalToUpdatedCorrespondence;
|
||||
bool m_isUpdateRequired = false;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "ovkCComment.h"
|
||||
#include "ovkCScenario.h"
|
||||
|
||||
#include "../ovkCObjectVisitorContext.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CComment::CComment(const IKernelContext& ctx, CScenario& rOwnerScenario)
|
||||
: TAttributable<TKernelObject<IComment>>(ctx), m_rOwnerScenario(rOwnerScenario), m_text("") {}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CComment::setIdentifier(const CIdentifier& id)
|
||||
{
|
||||
if (m_id != CIdentifier::undefined() || id == CIdentifier::undefined()) { return false; }
|
||||
m_id = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CComment::setText(const CString& sText)
|
||||
{
|
||||
m_text = sText;
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CComment::initializeFromExistingComment(const IComment& rExisitingComment)
|
||||
{
|
||||
m_text = rExisitingComment.getText();
|
||||
|
||||
CIdentifier id = rExisitingComment.getNextAttributeIdentifier(CIdentifier::undefined());
|
||||
while (id != CIdentifier::undefined())
|
||||
{
|
||||
addAttribute(id, rExisitingComment.getAttributeValue(id));
|
||||
id = rExisitingComment.getNextAttributeIdentifier(id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CComment::acceptVisitor(IObjectVisitor& rObjectVisitor)
|
||||
{
|
||||
CObjectVisitorContext context(getKernelContext());
|
||||
return rObjectVisitor.processBegin(context, *this) && rObjectVisitor.processEnd(context, *this);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include "ovkTAttributable.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScenario;
|
||||
|
||||
class CComment final : public TAttributable<TKernelObject<IComment>>
|
||||
{
|
||||
public:
|
||||
|
||||
CComment(const IKernelContext& ctx, CScenario& rOwnerScenario);
|
||||
~CComment() override {}
|
||||
CIdentifier getIdentifier() const override { return m_id; }
|
||||
CString getText() const override { return m_text; }
|
||||
bool setIdentifier(const CIdentifier& id) override;
|
||||
bool setText(const CString& sText) override;
|
||||
bool initializeFromExistingComment(const IComment& rExisitingComment) override;
|
||||
bool acceptVisitor(IObjectVisitor& rObjectVisitor) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TAttributable<TKernelObject<IComment>>, OVK_ClassId_Kernel_Scenario_Comment)
|
||||
|
||||
protected:
|
||||
|
||||
CScenario& m_rOwnerScenario;
|
||||
|
||||
CIdentifier m_id = CIdentifier::undefined();
|
||||
CString m_text;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,76 @@
|
||||
#include "ovkCLink.h"
|
||||
#include "ovkCScenario.h"
|
||||
|
||||
#include "../ovkCObjectVisitorContext.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
bool CLink::initializeFromExistingLink(const ILink& link)
|
||||
{
|
||||
m_id = link.getIdentifier();
|
||||
m_srcBoxID = link.getSourceBoxIdentifier();
|
||||
m_dstBoxID = link.getTargetBoxIdentifier();
|
||||
m_srcBoxOutputID = link.getSourceBoxOutputIdentifier();
|
||||
m_dstBoxInputID = link.getTargetBoxInputIdentifier();
|
||||
m_srcOutputIdx = link.getSourceBoxOutputIndex();
|
||||
m_dstInputIdx = link.getTargetBoxInputIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CLink::setIdentifier(const CIdentifier& identifier)
|
||||
{
|
||||
m_id = identifier;
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CLink::setSource(const CIdentifier& boxId, const size_t boxOutputIdx, const CIdentifier boxOutputID)
|
||||
{
|
||||
m_srcBoxID = boxId;
|
||||
m_srcOutputIdx = boxOutputIdx;
|
||||
m_srcBoxOutputID = boxOutputID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLink::setTarget(const CIdentifier& boxId, const size_t boxInputIdx, const CIdentifier boxInputID)
|
||||
{
|
||||
m_dstBoxID = boxId;
|
||||
m_dstInputIdx = boxInputIdx;
|
||||
m_dstBoxInputID = boxInputID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLink::getSource(CIdentifier& boxId, size_t& boxOutputIdx, CIdentifier& boxOutputID) const
|
||||
{
|
||||
boxId = m_srcBoxID;
|
||||
boxOutputIdx = m_srcOutputIdx;
|
||||
boxOutputID = m_srcBoxOutputID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLink::getTarget(CIdentifier& dstBoxID, size_t& boxInputIndex, CIdentifier& dstBoxInputID) const
|
||||
{
|
||||
dstBoxID = m_dstBoxID;
|
||||
boxInputIndex = m_dstInputIdx;
|
||||
dstBoxInputID = m_dstBoxInputID;
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CLink::acceptVisitor(IObjectVisitor& visitor)
|
||||
{
|
||||
CObjectVisitorContext context(getKernelContext());
|
||||
return visitor.processBegin(context, *this) && visitor.processEnd(context, *this);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include "ovkTAttributable.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScenario;
|
||||
|
||||
class CLink final : public TAttributable<TKernelObject<ILink>>
|
||||
{
|
||||
public:
|
||||
|
||||
CLink(const IKernelContext& ctx, CScenario& ownerScenario) : TAttributable<TKernelObject<ILink>>(ctx), m_ownerScenario(ownerScenario) {}
|
||||
bool initializeFromExistingLink(const ILink& link) override;
|
||||
bool setIdentifier(const CIdentifier& identifier) override;
|
||||
CIdentifier getIdentifier() const override { return m_id; }
|
||||
bool setSource(const CIdentifier& boxId, size_t boxOutputIdx, CIdentifier boxOutputID) override;
|
||||
bool setTarget(const CIdentifier& boxId, size_t boxInputIdx, CIdentifier boxInputID) override;
|
||||
|
||||
bool getSource(CIdentifier& boxId, size_t& boxOutputIdx, CIdentifier& boxOutputID) const override;
|
||||
CIdentifier getSourceBoxIdentifier() const override { return m_srcBoxID; }
|
||||
size_t getSourceBoxOutputIndex() const override { return m_srcOutputIdx; }
|
||||
CIdentifier getSourceBoxOutputIdentifier() const override { return m_srcBoxOutputID; }
|
||||
|
||||
bool getTarget(CIdentifier& dstBoxID, size_t& boxInputIndex, CIdentifier& dstBoxInputID) const override;
|
||||
CIdentifier getTargetBoxIdentifier() const override { return m_dstBoxID; }
|
||||
size_t getTargetBoxInputIndex() const override { return m_dstInputIdx; }
|
||||
CIdentifier getTargetBoxInputIdentifier() const override { return m_dstBoxInputID; }
|
||||
|
||||
bool acceptVisitor(IObjectVisitor& visitor) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TAttributable<TKernelObject<ILink>>, OVK_ClassId_Kernel_Scenario_Link)
|
||||
|
||||
protected:
|
||||
|
||||
CScenario& m_ownerScenario;
|
||||
CIdentifier m_id = CIdentifier::undefined();
|
||||
CIdentifier m_srcBoxID = CIdentifier::undefined();
|
||||
CIdentifier m_dstBoxID = CIdentifier::undefined();
|
||||
size_t m_srcOutputIdx = 0;
|
||||
CIdentifier m_srcBoxOutputID = CIdentifier::undefined();
|
||||
size_t m_dstInputIdx = 0;
|
||||
CIdentifier m_dstBoxInputID = CIdentifier::undefined();
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include "ovkCMetadata.h"
|
||||
#include "ovkCScenario.h"
|
||||
|
||||
#include "../ovkCObjectVisitorContext.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
bool CMetadata::setIdentifier(const CIdentifier& identifier)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_id == CIdentifier::undefined(),
|
||||
"Metadata [" << m_id.str() << "] in scenario [" << m_ownerScenario.getIdentifier() << "] already has an identifier.",
|
||||
ErrorType::BadCall);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(identifier != CIdentifier::undefined(),
|
||||
"Attempted to assign undefined identifier to Metadata in scenario [" << m_ownerScenario.getIdentifier() << "].",
|
||||
ErrorType::BadArgument);
|
||||
|
||||
m_id = identifier;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMetadata::setType(const CIdentifier& typeID)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(typeID != CIdentifier::undefined(),
|
||||
"Attempted to assign undefined typeID to Metadata [" << m_id.str() << "] in scenario [" << m_ownerScenario.getIdentifier() << "].",
|
||||
ErrorType::BadArgument);
|
||||
|
||||
m_type = typeID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMetadata::setData(const CString& data)
|
||||
{
|
||||
m_data = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CMetadata::initializeFromExistingMetadata(const IMetadata& existingMetadata)
|
||||
{
|
||||
m_data = existingMetadata.getData();
|
||||
m_type = existingMetadata.getType();
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CMetadata::acceptVisitor(IObjectVisitor& objectVisitor)
|
||||
{
|
||||
CObjectVisitorContext objectVisitorContext(this->getKernelContext());
|
||||
return objectVisitor.processBegin(objectVisitorContext, *this) && objectVisitor.processEnd(objectVisitorContext, *this);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/kernel/scenario/ovIMetadata.h>
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScenario;
|
||||
|
||||
class CMetadata final : public TKernelObject<IMetadata>
|
||||
{
|
||||
public:
|
||||
|
||||
CMetadata(const IKernelContext& ctx, CScenario& ownerScenario) : TKernelObject<IMetadata>(ctx), m_ownerScenario(ownerScenario), m_data("") {}
|
||||
~CMetadata() override {}
|
||||
|
||||
CIdentifier getIdentifier() const override { return m_id; }
|
||||
CIdentifier getType() const override { return m_type; }
|
||||
CString getData() const override { return m_data; }
|
||||
bool setIdentifier(const CIdentifier& identifier) override;
|
||||
bool setType(const CIdentifier& typeID) override;
|
||||
bool setData(const CString& data) override;
|
||||
|
||||
bool initializeFromExistingMetadata(const IMetadata& existingMetadata) override;
|
||||
|
||||
bool acceptVisitor(IObjectVisitor& objectVisitor) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IMetadata>, OVK_ClassId_Kernel_Scenario_Metadata)
|
||||
|
||||
private:
|
||||
|
||||
CScenario& m_ownerScenario;
|
||||
|
||||
CIdentifier m_id = CIdentifier::undefined();
|
||||
CIdentifier m_type = CIdentifier::undefined();
|
||||
CString m_data;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+1460
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include "ovkTBox.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
typedef TBox<IBox> CBox;
|
||||
class CComment;
|
||||
class CMetadata;
|
||||
class CLink;
|
||||
|
||||
class CScenario final : public TBox<IScenario>
|
||||
{
|
||||
public:
|
||||
|
||||
CScenario(const IKernelContext& ctx, const CIdentifier& identifier);
|
||||
~CScenario() override { this->clear(); }
|
||||
|
||||
bool clear() override;
|
||||
bool merge(const IScenario& scenario, IScenarioMergeCallback* scenarioMergeCallback, bool mergeSettings, bool preserveIDs) override;
|
||||
|
||||
CIdentifier getNextBoxIdentifier(const CIdentifier& previousID) const override;
|
||||
bool isBox(const CIdentifier& boxID) const override;
|
||||
const IBox* getBoxDetails(const CIdentifier& boxID) const override;
|
||||
IBox* getBoxDetails(const CIdentifier& boxID) override;
|
||||
bool addBox(CIdentifier& boxID, const CIdentifier& suggestedBoxID) override;
|
||||
bool addBox(CIdentifier& boxID, const IBox& box, const CIdentifier& suggestedBoxID) override;
|
||||
bool addBox(CIdentifier& boxID, const CIdentifier& boxAlgorithmID, const CIdentifier& suggestedBoxID) override;
|
||||
bool addBox(CIdentifier& boxID, const Plugins::IBoxAlgorithmDesc& boxAlgorithmDesc, const CIdentifier& suggestedBoxID) override;
|
||||
bool removeBox(const CIdentifier& boxID) override;
|
||||
|
||||
CIdentifier getNextCommentIdentifier(const CIdentifier& previousID) const override;
|
||||
bool isComment(const CIdentifier& commentID) const override;
|
||||
const IComment* getCommentDetails(const CIdentifier& commentID) const override;
|
||||
IComment* getCommentDetails(const CIdentifier& commentID) override;
|
||||
bool addComment(CIdentifier& commentID, const CIdentifier& suggestedCommentID) override;
|
||||
bool addComment(CIdentifier& commentID, const IComment& comment, const CIdentifier& suggestedCommentID) override;
|
||||
bool removeComment(const CIdentifier& commentID) override;
|
||||
|
||||
CIdentifier getNextMetadataIdentifier(const CIdentifier& previousID) const override;
|
||||
bool isMetadata(const CIdentifier& metadataID) const override;
|
||||
const IMetadata* getMetadataDetails(const CIdentifier& metadataID) const override;
|
||||
IMetadata* getMetadataDetails(const CIdentifier& metadataID) override;
|
||||
bool addMetadata(CIdentifier& metadataID, const CIdentifier& suggestedMetadataID) override;
|
||||
bool removeMetadata(const CIdentifier& metadataID) override;
|
||||
|
||||
CIdentifier getNextLinkIdentifier(const CIdentifier& previousID) const override;
|
||||
|
||||
CIdentifier getNextLinkIdentifierFromBox(const CIdentifier& previousID, const CIdentifier& boxID) const override;
|
||||
CIdentifier getNextLinkIdentifierFromBoxOutput(const CIdentifier& previousID, const CIdentifier& boxID, size_t index) const override;
|
||||
CIdentifier getNextLinkIdentifierToBox(const CIdentifier& previousID, const CIdentifier& boxID) const override;
|
||||
CIdentifier getNextLinkIdentifierToBoxInput(const CIdentifier& previousID, const CIdentifier& boxID, size_t index) const override;
|
||||
bool isLink(const CIdentifier& boxID) const override;
|
||||
|
||||
bool setHasIO(bool hasIO) override;
|
||||
bool hasIO() const override;
|
||||
bool setScenarioInputLink(size_t scenarioInputIdx, const CIdentifier& boxID, size_t boxInputIdx) override;
|
||||
bool setScenarioInputLink(size_t scenarioInputIdx, const CIdentifier& boxID, const CIdentifier& boxInputID) override;
|
||||
bool setScenarioOutputLink(size_t scenarioOutputIdx, const CIdentifier& boxID, size_t boxOutputIdx) override;
|
||||
bool setScenarioOutputLink(size_t scenarioOutputIdx, const CIdentifier& boxID, const CIdentifier& boxOutputID) override;
|
||||
bool getScenarioInputLink(size_t scenarioInputIdx, CIdentifier& boxID, size_t& boxInputIdx) const override;
|
||||
bool getScenarioInputLink(size_t scenarioInputIdx, CIdentifier& boxID, CIdentifier& boxOutputID) const override;
|
||||
bool getScenarioOutputLink(size_t scenarioOutputIdx, CIdentifier& boxID, size_t& boxOutputIdx) const override;
|
||||
bool getScenarioOutputLink(size_t scenarioOutputIdx, CIdentifier& boxID, CIdentifier& boxOutputID) const override;
|
||||
bool removeScenarioInputLink(size_t scenarioInputIdx, const CIdentifier& boxID, size_t boxInputIdx) override;
|
||||
bool removeScenarioOutputLink(size_t scenarioOutputIdx, const CIdentifier& boxID, size_t boxOutputIdx) override;
|
||||
|
||||
bool removeScenarioInput(size_t index) override;
|
||||
bool removeScenarioOutput(size_t index) override;
|
||||
|
||||
const ILink* getLinkDetails(const CIdentifier& linkID) const override;
|
||||
ILink* getLinkDetails(const CIdentifier& linkID) override;
|
||||
|
||||
bool connect(CIdentifier& linkID, const CIdentifier& srcBoxID, const size_t srcBoxOutputIdx, const CIdentifier& dstBoxID,
|
||||
const size_t dstBoxInputIdx, const CIdentifier& suggestedLinkID) override;
|
||||
bool connect(CIdentifier& linkID, const CIdentifier& srcBoxID, const CIdentifier& srcBoxOutputID, const CIdentifier& dstBoxID,
|
||||
const CIdentifier& dstBoxInputID, const CIdentifier& suggestedLinkID) override;
|
||||
bool disconnect(const CIdentifier& srcBoxID, size_t srcBoxOutputIdx, const CIdentifier& dstBoxID, size_t dstBoxInputIdx) override;
|
||||
bool disconnect(const CIdentifier& srcBoxID, const CIdentifier& srcBoxOutputID, const CIdentifier& dstBoxID, const CIdentifier& dstBoxInputID) override;
|
||||
bool disconnect(const CIdentifier& linkID) override;
|
||||
|
||||
bool getSourceBoxOutputIndex(const CIdentifier& srcBoxID, const CIdentifier& srcBoxOutputID, size_t& srcBoxOutputIdx) override;
|
||||
bool getTargetBoxInputIndex(const CIdentifier& dstBoxID, const CIdentifier& dstBoxInputID, size_t& dstBoxInputIdx) override;
|
||||
bool getSourceBoxOutputIdentifier(const CIdentifier& srcBoxID, const size_t& srcBoxOutputIdx, CIdentifier& srcBoxOutputID) override;
|
||||
bool getTargetBoxInputIdentifier(const CIdentifier& dstBoxID, const size_t& dstBoxInputIdx, CIdentifier& dstBoxInputID) override;
|
||||
|
||||
bool applyLocalSettings() override;
|
||||
bool checkSettings(IConfigurationManager* configurationManager) override;
|
||||
|
||||
bool isBoxOutdated(const CIdentifier& boxId);
|
||||
bool checkOutdatedBoxes() override;
|
||||
bool hasOutdatedBox() override;
|
||||
|
||||
CIdentifier getNextOutdatedBoxIdentifier(const CIdentifier& previousID) const override;
|
||||
|
||||
bool isMetabox() override;
|
||||
|
||||
void getBoxIdentifierList(CIdentifier** listID, size_t* size) const override;
|
||||
void getCommentIdentifierList(CIdentifier** listID, size_t* size) const override;
|
||||
void getMetadataIdentifierList(CIdentifier** listID, size_t* size) const override;
|
||||
void getLinkIdentifierList(CIdentifier** listID, size_t* size) const override;
|
||||
void getLinkIdentifierFromBoxList(const CIdentifier& boxID, CIdentifier** listID, size_t* size) const override;
|
||||
void getLinkIdentifierFromBoxOutputList(const CIdentifier& boxID, size_t index, CIdentifier** listID, size_t* size) const override;
|
||||
void getLinkIdentifierToBoxList(const CIdentifier& boxID, CIdentifier** listID, size_t* size) const override;
|
||||
void getLinkIdentifierToBoxInputList(const CIdentifier& boxID, size_t index, CIdentifier** listID, size_t* size) const override;
|
||||
void getOutdatedBoxIdentifierList(CIdentifier** listID, size_t* size) const override;
|
||||
void releaseIdentifierList(CIdentifier* listID) const override;
|
||||
|
||||
|
||||
bool acceptVisitor(IObjectVisitor& objectVisitor) override;
|
||||
|
||||
bool updateBox(const CIdentifier& boxID) override;
|
||||
|
||||
bool containsBoxWithDeprecatedInterfacors() const override;
|
||||
|
||||
bool removeDeprecatedInterfacorsFromBox(const CIdentifier& boxID) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TBox<IScenario>, OVK_ClassId_Kernel_Scenario_Scenario)
|
||||
|
||||
private:
|
||||
CIdentifier getUnusedIdentifier(const CIdentifier& suggestedID) const;
|
||||
|
||||
std::map<CIdentifier, CBox*> m_boxes;
|
||||
std::map<CIdentifier, CComment*> m_comments;
|
||||
std::map<CIdentifier, CMetadata*> m_metadatas;
|
||||
std::map<CIdentifier, CLink*> m_links;
|
||||
std::map<CIdentifier, std::shared_ptr<CBox>> m_outdatedBoxes;
|
||||
std::map<EBoxInterfacorType, std::map<CIdentifier, std::map<size_t, size_t>>> m_updatedBoxIOCorrespondence;
|
||||
|
||||
|
||||
bool m_hasIO = false;
|
||||
|
||||
mutable std::vector<std::pair<CIdentifier, size_t>> m_scenarioInputLinks;
|
||||
mutable std::vector<std::pair<CIdentifier, size_t>> m_scenarioOutputLinks;
|
||||
|
||||
// Helper members. These are used for quick lookup of next identifiers for the purpose
|
||||
// of the getNextMetadataIdentifier function.
|
||||
std::map<CIdentifier, CIdentifier> m_nextMetadataID;
|
||||
CIdentifier m_firstMetadataID = CIdentifier::undefined();
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+585
@@ -0,0 +1,585 @@
|
||||
#include "ovkCScenarioManager.h"
|
||||
#include "ovkCScenario.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fs/Files.h>
|
||||
#include <cassert>
|
||||
#include <openvibe/kernel/scenario/ovIAlgorithmScenarioImporter.h>
|
||||
#include <openvibe/kernel/scenario/ovIAlgorithmScenarioExporter.h>
|
||||
#include "../../tools/ovkSBoxProto.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
CScenarioManager::CScenarioManager(const IKernelContext& ctx) : TKernelObject<IScenarioManager>(ctx) {}
|
||||
|
||||
CScenarioManager::~CScenarioManager() { for (auto i = m_scenarios.begin(); i != m_scenarios.end(); ++i) { delete i->second; } }
|
||||
|
||||
void CScenarioManager::cloneScenarioImportersAndExporters(const IScenarioManager& scenarioManager)
|
||||
{
|
||||
CIdentifier importContextId = CIdentifier::undefined();
|
||||
// Copy the registered importers from the parent Scenario Manager
|
||||
while ((importContextId = scenarioManager.getNextScenarioImportContext(importContextId)) != CIdentifier::undefined())
|
||||
{
|
||||
CString fileNameExtension = "";
|
||||
while ((fileNameExtension = scenarioManager.getNextScenarioImporter(importContextId, fileNameExtension)) != CString(""))
|
||||
{
|
||||
CIdentifier algorithmId = scenarioManager.getScenarioImporterAlgorithmIdentifier(importContextId, fileNameExtension);
|
||||
|
||||
this->registerScenarioImporter(importContextId, fileNameExtension, algorithmId);
|
||||
}
|
||||
}
|
||||
|
||||
CIdentifier exportContextId = CIdentifier::undefined();
|
||||
while ((exportContextId = scenarioManager.getNextScenarioExportContext(exportContextId)) != CIdentifier::undefined())
|
||||
{
|
||||
CString fileNameExtension = "";
|
||||
while ((fileNameExtension = scenarioManager.getNextScenarioExporter(exportContextId, fileNameExtension)) != CString(""))
|
||||
{
|
||||
CIdentifier algorithmId = scenarioManager.getScenarioExporterAlgorithmIdentifier(exportContextId, fileNameExtension);
|
||||
|
||||
this->registerScenarioExporter(exportContextId, fileNameExtension, algorithmId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CIdentifier CScenarioManager::getNextScenarioIdentifier(const CIdentifier& previousID) const
|
||||
{
|
||||
std::map<CIdentifier, CScenario*>::const_iterator itScenario;
|
||||
|
||||
if (previousID == CIdentifier::undefined()) { itScenario = m_scenarios.begin(); }
|
||||
else
|
||||
{
|
||||
itScenario = m_scenarios.find(previousID);
|
||||
if (itScenario == m_scenarios.end()) { return CIdentifier::undefined(); }
|
||||
++itScenario;
|
||||
}
|
||||
|
||||
return itScenario != m_scenarios.end() ? itScenario->first : CIdentifier::undefined();
|
||||
}
|
||||
|
||||
bool CScenarioManager::isScenario(const CIdentifier& scenarioID) const { return m_scenarios.find(scenarioID) != m_scenarios.end(); }
|
||||
|
||||
bool CScenarioManager::createScenario(CIdentifier& scenarioID)
|
||||
{
|
||||
//create scenario object
|
||||
scenarioID = getUnusedIdentifier();
|
||||
CScenario* scenario = new CScenario(getKernelContext(), scenarioID);
|
||||
m_scenarios[scenarioID] = scenario;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScenarioManager::importScenario(CIdentifier& scenarioID, const IMemoryBuffer& iMemoryBuffer, const CIdentifier& scenarioImporterAlgorithmID)
|
||||
{
|
||||
scenarioID = CIdentifier::undefined();
|
||||
|
||||
OV_ERROR_UNLESS_KRF(this->createScenario(scenarioID), "Error creating new scenario", Kernel::ErrorType::BadResourceCreation);
|
||||
|
||||
const auto releaseScenario = [&]()
|
||||
{
|
||||
// use a fatal here because a release failure while creation succeeded
|
||||
// means we are in an unexpected state
|
||||
OV_FATAL_UNLESS_K(this->releaseScenario(scenarioID), "Releasing just created scenario failed for " << scenarioID.str(),
|
||||
ErrorType::Internal);
|
||||
scenarioID = CIdentifier::undefined();
|
||||
};
|
||||
|
||||
IScenario& newScenarioInstance = this->getScenario(scenarioID);
|
||||
|
||||
if (!iMemoryBuffer.getSize())
|
||||
{
|
||||
releaseScenario();
|
||||
OV_ERROR_KRF("Buffer containing scenario data is empty", Kernel::ErrorType::BadValue);
|
||||
}
|
||||
|
||||
CIdentifier importerInstanceIdentifier = this->getKernelContext().getAlgorithmManager().createAlgorithm(scenarioImporterAlgorithmID);
|
||||
|
||||
if (importerInstanceIdentifier == CIdentifier::undefined())
|
||||
{
|
||||
releaseScenario();
|
||||
OV_ERROR_KRF("Can not create the requested scenario importer", Kernel::ErrorType::BadResourceCreation);
|
||||
}
|
||||
|
||||
IAlgorithmProxy* importer = &this->getKernelContext().getAlgorithmManager().getAlgorithm(importerInstanceIdentifier);
|
||||
|
||||
OV_FATAL_UNLESS_K(
|
||||
importer,
|
||||
"Importer with id " << importerInstanceIdentifier.str() << " not found although it has just been created",
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
const auto releaseAlgorithm = [&]()
|
||||
{
|
||||
// use a fatal here because a release failure while creation succeeded
|
||||
// means we are in an unexpected state
|
||||
OV_FATAL_UNLESS_K(
|
||||
this->getKernelContext().getAlgorithmManager().releaseAlgorithm(*importer),
|
||||
"Releasing just created algorithm failed for " << importerInstanceIdentifier.str(),
|
||||
ErrorType::Internal);
|
||||
};
|
||||
|
||||
if (!importer->initialize())
|
||||
{
|
||||
releaseScenario();
|
||||
releaseAlgorithm();
|
||||
OV_ERROR_KRF("Can not initialize the requested scenario importer", Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
IParameter* memoryBufferParameter = importer->getInputParameter(OV_Algorithm_ScenarioImporter_InputParameterId_MemoryBuffer);
|
||||
IParameter* scenarioParameter = importer->getOutputParameter(OV_Algorithm_ScenarioImporter_OutputParameterId_Scenario);
|
||||
|
||||
if (!(memoryBufferParameter && scenarioParameter))
|
||||
{
|
||||
releaseScenario();
|
||||
releaseAlgorithm();
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
memoryBufferParameter,
|
||||
"The requested importer does not have a MemoryBuffer input parameter with scenarioID " <<
|
||||
OV_Algorithm_ScenarioImporter_InputParameterId_MemoryBuffer,
|
||||
ErrorType::BadInput);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
scenarioParameter,
|
||||
"The requested importer does not have a Scenario output parameter with scenarioID " << OV_Algorithm_ScenarioImporter_OutputParameterId_Scenario,
|
||||
ErrorType::BadOutput);
|
||||
}
|
||||
|
||||
|
||||
TParameterHandler<const IMemoryBuffer*> memoryBufferParameterHandler(memoryBufferParameter);
|
||||
TParameterHandler<IScenario*> scenarioParameterHandler(scenarioParameter);
|
||||
|
||||
memoryBufferParameterHandler = &iMemoryBuffer;
|
||||
scenarioParameterHandler = &newScenarioInstance;
|
||||
|
||||
if (!importer->process())
|
||||
{
|
||||
releaseScenario();
|
||||
releaseAlgorithm();
|
||||
OV_ERROR_KRF("Can not process data using the requested scenario importer", Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
if (!importer->uninitialize())
|
||||
{
|
||||
releaseScenario();
|
||||
releaseAlgorithm();
|
||||
OV_ERROR_KRF("Can not uninitialize the requested scenario importer", Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
releaseAlgorithm();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScenarioManager::importScenarioFromFile(CIdentifier& scenarioID, const CString& fileName, const CIdentifier& scenarioImporterAlgorithmID)
|
||||
{
|
||||
scenarioID = CIdentifier::undefined();
|
||||
|
||||
CMemoryBuffer memoryBuffer;
|
||||
|
||||
FILE* inputFile = FS::Files::open(fileName, "rb");
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
inputFile,
|
||||
"Can not open scenario file '" << fileName << "'",
|
||||
ErrorType::BadFileRead);
|
||||
|
||||
fseek(inputFile, 0, SEEK_END);
|
||||
memoryBuffer.setSize(size_t(ftell(inputFile)), true);
|
||||
fseek(inputFile, 0, SEEK_SET);
|
||||
|
||||
if (fread(reinterpret_cast<char*>(memoryBuffer.getDirectPointer()), size_t(memoryBuffer.getSize()), 1, inputFile) != 1)
|
||||
{
|
||||
fclose(inputFile);
|
||||
OV_ERROR_KRF("Problem reading scenario file '" << fileName << "'", Kernel::ErrorType::BadFileRead);
|
||||
}
|
||||
fclose(inputFile);
|
||||
|
||||
return this->importScenario(scenarioID, memoryBuffer, scenarioImporterAlgorithmID);
|
||||
}
|
||||
|
||||
bool CScenarioManager::importScenarioFromFile(CIdentifier& scenarioID, const CIdentifier& importContext, const CString& fileName)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_importers.count(importContext),
|
||||
"The import context " << importContext.str() << " has no associated importers",
|
||||
ErrorType::Internal);
|
||||
std::vector<char> fileNameExtension;
|
||||
fileNameExtension.resize(fileName.length() + 1);
|
||||
FS::Files::getFilenameExtension(fileName.toASCIIString(), &fileNameExtension[0]);
|
||||
OV_ERROR_UNLESS_KRF(m_importers[importContext].count(&fileNameExtension[0]),
|
||||
"The import context " << importContext.str() << " has no associated importers for extension [" << &fileNameExtension[0] << "]",
|
||||
ErrorType::Internal);
|
||||
return this->importScenarioFromFile(scenarioID, fileName, m_importers[importContext][&fileNameExtension[0]]);
|
||||
}
|
||||
|
||||
bool CScenarioManager::registerScenarioImporter(const CIdentifier& importContext, const CString& fileNameExtension,
|
||||
const CIdentifier& scenarioImporterAlgorithmIdentifier)
|
||||
{
|
||||
if (!m_importers.count(importContext)) { m_importers[importContext] = std::map<std::string, CIdentifier>(); }
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!m_importers[importContext].count(fileNameExtension.toASCIIString()),
|
||||
"The file name extension [" << fileNameExtension << "] already has an importer registered for context " << importContext.str(),
|
||||
ErrorType::Internal);
|
||||
|
||||
m_importers[importContext][fileNameExtension.toASCIIString()] = scenarioImporterAlgorithmIdentifier;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScenarioManager::unregisterScenarioImporter(const CIdentifier& importContext, const CString& fileNameExtension)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_importers.count(importContext),
|
||||
"The import context " << importContext.str() << " has no associated importers",
|
||||
ErrorType::Internal);
|
||||
OV_ERROR_UNLESS_KRF(m_importers[importContext].count(fileNameExtension.toASCIIString()),
|
||||
"The import context " << importContext.str() << " has no associated importers for extension [" << fileNameExtension << "]",
|
||||
ErrorType::Internal);
|
||||
|
||||
auto& contextImporters = m_importers[importContext];
|
||||
|
||||
for (auto it = contextImporters.begin(); it != contextImporters.end();)
|
||||
{
|
||||
if (it->first == fileNameExtension.toASCIIString()) { it = contextImporters.erase(it); }
|
||||
else { ++it; }
|
||||
}
|
||||
for (auto it = m_importers.begin(); it != m_importers.end();)
|
||||
{
|
||||
if (it->second.empty()) { it = m_importers.erase(it); }
|
||||
else { ++it; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CScenarioManager::getNextScenarioImportContext(const CIdentifier& importContext) const
|
||||
{
|
||||
if (m_importers.empty()) { return CIdentifier::undefined(); }
|
||||
|
||||
if (importContext == CIdentifier::undefined()) { return m_importers.cbegin()->first; }
|
||||
|
||||
auto current = m_importers.find(importContext);
|
||||
if (current == m_importers.end() || ++current == m_importers.end()) { return CIdentifier::undefined(); }
|
||||
|
||||
return current->first;
|
||||
}
|
||||
|
||||
CString CScenarioManager::getNextScenarioImporter(const CIdentifier& importContext, const CString& fileNameExtension) const
|
||||
{
|
||||
if (m_importers.empty() || !m_importers.count(importContext)) { return ""; }
|
||||
|
||||
const auto& scenarioImportContextMap = m_importers.at(importContext);
|
||||
|
||||
if (fileNameExtension == CString("")) { return scenarioImportContextMap.cbegin()->first.c_str(); }
|
||||
|
||||
auto current = scenarioImportContextMap.find(fileNameExtension.toASCIIString());
|
||||
if (current == scenarioImportContextMap.end() || ++current == scenarioImportContextMap.end()) { return ""; }
|
||||
|
||||
return current->first.c_str();
|
||||
}
|
||||
|
||||
CIdentifier CScenarioManager::getScenarioImporterAlgorithmIdentifier(const CIdentifier& importContext, const CString& fileNameExtension) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRU(
|
||||
!m_importers.empty() && m_importers.count(importContext) && m_importers.at(importContext).count(fileNameExtension.toASCIIString(
|
||||
)),
|
||||
"Scenario importer not found",
|
||||
ErrorType::OutOfBound);
|
||||
|
||||
return m_importers.at(importContext).at(fileNameExtension.toASCIIString());
|
||||
}
|
||||
|
||||
bool CScenarioManager::exportScenario(IMemoryBuffer& oMemoryBuffer, const CIdentifier& scenarioID,
|
||||
const CIdentifier& scenarioExporterAlgorithmID) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
m_scenarios.find(scenarioID) != m_scenarios.end(),
|
||||
"Scenario with identifier " << scenarioID.str() << " does not exist.",
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
// If the scenario is a metabox, we will save its prototype hash into an attribute of the scenario
|
||||
// that way the standalone scheduler can check whether metaboxes included inside need updating.
|
||||
IScenario& scenario = this->getScenario(scenarioID);
|
||||
|
||||
|
||||
if (scenario.isMetabox())
|
||||
{
|
||||
SBoxProto metaboxProto(getKernelContext().getTypeManager());
|
||||
|
||||
for (size_t scenarioInputIdx = 0; scenarioInputIdx < scenario.getInputCount(); ++scenarioInputIdx)
|
||||
{
|
||||
CIdentifier id;
|
||||
CString name;
|
||||
CIdentifier typeID;
|
||||
|
||||
scenario.getInterfacorIdentifier(Input, scenarioInputIdx, id);
|
||||
scenario.getInputType(scenarioInputIdx, typeID);
|
||||
scenario.getInputName(scenarioInputIdx, name);
|
||||
|
||||
metaboxProto.addInput(name, typeID, id, true);
|
||||
}
|
||||
|
||||
for (size_t scenarioOutputIdx = 0; scenarioOutputIdx < scenario.getOutputCount(); ++scenarioOutputIdx)
|
||||
{
|
||||
CIdentifier id;
|
||||
CString name;
|
||||
CIdentifier typeID;
|
||||
|
||||
scenario.getInterfacorIdentifier(Output, scenarioOutputIdx, id);
|
||||
scenario.getOutputType(scenarioOutputIdx, typeID);
|
||||
scenario.getOutputName(scenarioOutputIdx, name);
|
||||
|
||||
metaboxProto.addOutput(name, typeID, id, true);
|
||||
}
|
||||
|
||||
for (size_t scenarioSettingIdx = 0; scenarioSettingIdx < scenario.getSettingCount(); ++scenarioSettingIdx)
|
||||
{
|
||||
CString name;
|
||||
CIdentifier typeID;
|
||||
CString defaultValue;
|
||||
CIdentifier id;
|
||||
|
||||
scenario.getSettingName(scenarioSettingIdx, name);
|
||||
scenario.getSettingType(scenarioSettingIdx, typeID);
|
||||
scenario.getSettingDefaultValue(scenarioSettingIdx, defaultValue);
|
||||
scenario.getInterfacorIdentifier(Setting, scenarioSettingIdx, id);
|
||||
|
||||
metaboxProto.addSetting(name, typeID, defaultValue, false, id, true);
|
||||
}
|
||||
|
||||
if (scenario.hasAttribute(OV_AttributeId_Scenario_MetaboxHash))
|
||||
{
|
||||
scenario.setAttributeValue(OV_AttributeId_Scenario_MetaboxHash, metaboxProto.m_hash.toString());
|
||||
}
|
||||
else { scenario.addAttribute(OV_AttributeId_Scenario_MetaboxHash, metaboxProto.m_hash.toString()); }
|
||||
}
|
||||
|
||||
CIdentifier exporterInstanceIdentifier = this->getKernelContext().getAlgorithmManager().createAlgorithm(scenarioExporterAlgorithmID);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
exporterInstanceIdentifier != CIdentifier::undefined(),
|
||||
"Can not create the requested scenario exporter",
|
||||
ErrorType::BadResourceCreation);
|
||||
|
||||
IAlgorithmProxy* exporter = &this->getKernelContext().getAlgorithmManager().getAlgorithm(exporterInstanceIdentifier);
|
||||
|
||||
OV_FATAL_UNLESS_K(
|
||||
exporter,
|
||||
"Exporter with id " << exporterInstanceIdentifier.str() << " not found although it has just been created",
|
||||
ErrorType::ResourceNotFound);
|
||||
|
||||
const auto releaseAlgorithm = [&]()
|
||||
{
|
||||
// use a fatal here because a release failure while creation succeeded
|
||||
// means we are in an unexpected state
|
||||
OV_FATAL_UNLESS_K(
|
||||
this->getKernelContext().getAlgorithmManager().releaseAlgorithm(*exporter),
|
||||
"Releasing just created algorithm failed for " << exporterInstanceIdentifier.str(),
|
||||
ErrorType::Internal);
|
||||
};
|
||||
|
||||
if (!exporter->initialize())
|
||||
{
|
||||
releaseAlgorithm();
|
||||
OV_ERROR_KRF("Can not initialize the requested scenario exporter", Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
IParameter* scenarioParameter = exporter->getInputParameter(OV_Algorithm_ScenarioExporter_InputParameterId_Scenario);
|
||||
IParameter* memoryBufferParameter = exporter->getOutputParameter(OV_Algorithm_ScenarioExporter_OutputParameterId_MemoryBuffer);
|
||||
|
||||
if (!(memoryBufferParameter && scenarioParameter))
|
||||
{
|
||||
releaseAlgorithm();
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
scenarioParameter,
|
||||
"The requested exporter does not have a Scenario input parameter with identifier " << OV_Algorithm_ScenarioExporter_InputParameterId_Scenario,
|
||||
ErrorType::BadInput);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
memoryBufferParameter,
|
||||
"The requested exporter does not have a MemoryBuffer output parameter with identifier " <<
|
||||
OV_Algorithm_ScenarioExporter_OutputParameterId_MemoryBuffer,
|
||||
ErrorType::BadOutput);
|
||||
}
|
||||
|
||||
TParameterHandler<IScenario*> scenarioParameterHandler(scenarioParameter);
|
||||
TParameterHandler<const IMemoryBuffer*> memoryBufferParameterHandler(memoryBufferParameter);
|
||||
|
||||
scenarioParameterHandler = &scenario;
|
||||
memoryBufferParameterHandler = &oMemoryBuffer;
|
||||
|
||||
if (!exporter->process())
|
||||
{
|
||||
releaseAlgorithm();
|
||||
OV_ERROR_KRF("Can not process data using the requested scenario exporter", Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
if (!exporter->uninitialize())
|
||||
{
|
||||
releaseAlgorithm();
|
||||
OV_ERROR_KRF("Can not uninitialize the requested scenario exporter", Kernel::ErrorType::Internal);
|
||||
}
|
||||
|
||||
releaseAlgorithm();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScenarioManager::exportScenarioToFile(const CString& fileName, const CIdentifier& scenarioID,
|
||||
const CIdentifier& scenarioExporterAlgorithmID) const
|
||||
{
|
||||
IScenario& scenario = this->getScenario(scenarioID);
|
||||
if (scenario.containsBoxWithDeprecatedInterfacors())
|
||||
{
|
||||
OV_WARNING_K(
|
||||
"Cannot export a scenario with pending deprecated I/O or Settings. Please remove them using the Designer."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
CMemoryBuffer memoryBuffer;
|
||||
this->exportScenario(memoryBuffer, scenarioID, scenarioExporterAlgorithmID);
|
||||
|
||||
std::ofstream outputFileStream;
|
||||
FS::Files::openOFStream(outputFileStream, fileName, std::ios::binary);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(
|
||||
outputFileStream.good(),
|
||||
"Failed to open file " << fileName,
|
||||
ErrorType::BadFileRead);
|
||||
|
||||
outputFileStream.write(reinterpret_cast<const char*>(memoryBuffer.getDirectPointer()), long(memoryBuffer.getSize()));
|
||||
outputFileStream.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScenarioManager::exportScenarioToFile(const CIdentifier& exportContext, const CString& fileName, const CIdentifier& scenarioID)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_exporters.count(exportContext),
|
||||
"The export context " << exportContext.str() << " has no associated exporters",
|
||||
ErrorType::Internal);
|
||||
std::vector<char> fileNameExtension;
|
||||
fileNameExtension.resize(fileName.length() + 1);
|
||||
FS::Files::getFilenameExtension(fileName.toASCIIString(), &fileNameExtension[0]);
|
||||
OV_ERROR_UNLESS_KRF(m_exporters[exportContext].count(&fileNameExtension[0]),
|
||||
"The export context " << exportContext.str() << " has no associated exporters for extension [" << &fileNameExtension[0] << "]",
|
||||
ErrorType::Internal);
|
||||
return this->exportScenarioToFile(fileName, scenarioID, m_exporters[exportContext][&fileNameExtension[0]]);
|
||||
}
|
||||
|
||||
bool CScenarioManager::registerScenarioExporter(const CIdentifier& exportContext, const CString& fileNameExtension,
|
||||
const CIdentifier& scenarioExporterAlgorithmIdentifier)
|
||||
{
|
||||
if (!m_exporters.count(exportContext)) { m_exporters[exportContext] = std::map<std::string, CIdentifier>(); }
|
||||
|
||||
OV_ERROR_UNLESS_KRF(!m_exporters[exportContext].count(fileNameExtension.toASCIIString()),
|
||||
"The file name extension [" << fileNameExtension << "] already has an exporter registered for context " << exportContext.str(),
|
||||
ErrorType::Internal);
|
||||
|
||||
m_exporters[exportContext][fileNameExtension.toASCIIString()] = scenarioExporterAlgorithmIdentifier;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScenarioManager::unregisterScenarioExporter(const CIdentifier& exportContext, const CString& fileNameExtension)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_exporters.count(exportContext),
|
||||
"The export context " << exportContext.str() << " has no associated exporters",
|
||||
ErrorType::Internal);
|
||||
OV_ERROR_UNLESS_KRF(m_exporters[exportContext].count(fileNameExtension.toASCIIString()),
|
||||
"The export context " << exportContext.str() << " has no associated exporters for extension [" << fileNameExtension << "]",
|
||||
ErrorType::Internal);
|
||||
|
||||
auto& contextExporters = m_exporters[exportContext];
|
||||
|
||||
for (auto it = contextExporters.begin(); it != contextExporters.end();)
|
||||
{
|
||||
if (it->first.c_str() == fileNameExtension.toASCIIString()) { it = contextExporters.erase(it); }
|
||||
else { ++it; }
|
||||
}
|
||||
for (auto it = m_exporters.begin(); it != m_exporters.end();)
|
||||
{
|
||||
if (it->second.empty()) { it = m_exporters.erase(it); }
|
||||
else { ++it; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CScenarioManager::getNextScenarioExportContext(const CIdentifier& exportContext) const
|
||||
{
|
||||
if (m_exporters.empty()) { return CIdentifier::undefined(); }
|
||||
|
||||
if (exportContext == CIdentifier::undefined()) { return m_exporters.cbegin()->first; }
|
||||
|
||||
auto current = m_exporters.find(exportContext);
|
||||
if (current == m_exporters.end() || ++current == m_exporters.end()) { return CIdentifier::undefined(); }
|
||||
|
||||
return current->first;
|
||||
}
|
||||
|
||||
CString CScenarioManager::getNextScenarioExporter(const CIdentifier& exportContext, const CString& fileNameExtension) const
|
||||
{
|
||||
if (m_exporters.empty() || !m_exporters.count(exportContext)) { return ""; }
|
||||
|
||||
const auto& scenarioExportContextMap = m_exporters.at(exportContext);
|
||||
|
||||
if (fileNameExtension == CString("")) { return scenarioExportContextMap.cbegin()->first.c_str(); }
|
||||
|
||||
auto current = scenarioExportContextMap.find(fileNameExtension.toASCIIString());
|
||||
if (current == scenarioExportContextMap.end() || ++current == scenarioExportContextMap.end()) { return ""; }
|
||||
|
||||
return current->first.c_str();
|
||||
}
|
||||
|
||||
CIdentifier CScenarioManager::getScenarioExporterAlgorithmIdentifier(const CIdentifier& exportContext, const CString& fileNameExtension) const
|
||||
{
|
||||
OV_ERROR_UNLESS_KRU(!m_exporters.empty() && m_exporters.count(exportContext) && m_exporters.at(exportContext).count(fileNameExtension.toASCIIString()),
|
||||
"Scenario importer not found", Kernel::ErrorType::OutOfBound);
|
||||
|
||||
return m_exporters.at(exportContext).at(fileNameExtension.toASCIIString());
|
||||
}
|
||||
|
||||
bool CScenarioManager::releaseScenario(const CIdentifier& scenarioID)
|
||||
{
|
||||
const auto it = m_scenarios.find(scenarioID);
|
||||
if (it == m_scenarios.end())
|
||||
{
|
||||
// error is handled on a higher level
|
||||
return false;
|
||||
}
|
||||
|
||||
CScenario* scenario = it->second;
|
||||
delete scenario;
|
||||
m_scenarios.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IScenario& CScenarioManager::getScenario(const CIdentifier& scenarioID)
|
||||
{
|
||||
const auto itScenario = m_scenarios.find(scenarioID);
|
||||
|
||||
// If the call is wrongly handled, and falls in this condition then next instruction causes a crash...
|
||||
// At least, here the abortion is handled!
|
||||
OV_FATAL_UNLESS_K(itScenario != m_scenarios.end(), "Scenario " << scenarioID.str() << " does not exist !", Kernel::ErrorType::ResourceNotFound);
|
||||
|
||||
return *itScenario->second;
|
||||
}
|
||||
|
||||
IScenario& CScenarioManager::getScenario(const CIdentifier& scenarioID) const { return const_cast<CScenarioManager*>(this)->getScenario(scenarioID); }
|
||||
|
||||
CIdentifier CScenarioManager::getUnusedIdentifier() const
|
||||
{
|
||||
uint64_t id = (uint64_t(rand()) << 32) + uint64_t(rand());
|
||||
CIdentifier res;
|
||||
std::map<CIdentifier, CScenario*>::const_iterator i;
|
||||
do
|
||||
{
|
||||
id++;
|
||||
res = CIdentifier(id);
|
||||
i = m_scenarios.find(res);
|
||||
} while (i != m_scenarios.end() || res == CIdentifier::undefined());
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovkTKernelObject.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScenario;
|
||||
|
||||
class CScenarioManager final : public TKernelObject<IScenarioManager>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CScenarioManager(const IKernelContext& ctx);
|
||||
~CScenarioManager() override;
|
||||
void cloneScenarioImportersAndExporters(const IScenarioManager& scenarioManager) override;
|
||||
CIdentifier getNextScenarioIdentifier(const CIdentifier& previousID) const override;
|
||||
bool isScenario(const CIdentifier& scenarioID) const override;
|
||||
bool createScenario(CIdentifier& scenarioID) override;
|
||||
bool importScenario(CIdentifier& scenarioID, const IMemoryBuffer& iMemoryBuffer, const CIdentifier& scenarioImporterAlgorithmID) override;
|
||||
bool importScenarioFromFile(CIdentifier& scenarioID, const CString& fileName, const CIdentifier& scenarioImporterAlgorithmID) override;
|
||||
bool importScenarioFromFile(CIdentifier& scenarioID, const CIdentifier& importContext, const CString& fileName) override;
|
||||
bool registerScenarioImporter(const CIdentifier& importContext, const CString& fileNameExtension,
|
||||
const CIdentifier& scenarioImporterAlgorithmIdentifier) override;
|
||||
bool unregisterScenarioImporter(const CIdentifier& importContext, const CString& fileNameExtension) override;
|
||||
CIdentifier getNextScenarioImportContext(const CIdentifier& importContext) const override;
|
||||
CString getNextScenarioImporter(const CIdentifier& importContext, const CString& fileNameExtension) const override;
|
||||
CIdentifier getScenarioImporterAlgorithmIdentifier(const CIdentifier& importContext, const CString& fileNameExtension) const override;
|
||||
bool exportScenario(IMemoryBuffer& oMemoryBuffer, const CIdentifier& scenarioID, const CIdentifier& scenarioExporterAlgorithmID) const override;
|
||||
bool exportScenarioToFile(const CString& fileName, const CIdentifier& scenarioID, const CIdentifier& scenarioExporterAlgorithmID) const override;
|
||||
bool exportScenarioToFile(const CIdentifier& exportContext, const CString& fileName, const CIdentifier& scenarioID) override;
|
||||
bool registerScenarioExporter(const CIdentifier& exportContext, const CString& fileNameExtension,
|
||||
const CIdentifier& scenarioExporterAlgorithmIdentifier) override;
|
||||
bool unregisterScenarioExporter(const CIdentifier& exportContext, const CString& fileNameExtension) override;
|
||||
CIdentifier getNextScenarioExportContext(const CIdentifier& exportContext) const override;
|
||||
CString getNextScenarioExporter(const CIdentifier& exportContext, const CString& fileNameExtension) const override;
|
||||
CIdentifier getScenarioExporterAlgorithmIdentifier(const CIdentifier& exportContext, const CString& fileNameExtension) const override;
|
||||
bool releaseScenario(const CIdentifier& scenarioID) override;
|
||||
IScenario& getScenario(const CIdentifier& scenarioID) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(TKernelObject<IScenarioManager>, OVK_ClassId_Kernel_Scenario_ScenarioManager)
|
||||
|
||||
protected:
|
||||
|
||||
CIdentifier getUnusedIdentifier() const;
|
||||
|
||||
std::map<CIdentifier, CScenario*> m_scenarios;
|
||||
private:
|
||||
/// Scenario Import Context -> File Name Extension -> Scenario Importer Identifier
|
||||
std::map<CIdentifier, std::map<std::string, CIdentifier>> m_importers;
|
||||
/// Scenario Export Context -> File Name Extension -> Scenario Exporter Identifier
|
||||
std::map<CIdentifier, std::map<std::string, CIdentifier>> m_exporters;
|
||||
|
||||
IScenario& getScenario(const CIdentifier& scenarioID) const;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#include "ovkCScenarioSettingKeywordParserCallback.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
bool CScenarioSettingKeywordParserCallback::expand(const CString& rStringToExpand, CString& rExpandedString) const
|
||||
{
|
||||
// In the case there is no value present we return an empty string
|
||||
rExpandedString = "";
|
||||
|
||||
// Expand the scenario directory
|
||||
if (rStringToExpand == CString("ScenarioDirectory"))
|
||||
{
|
||||
if (m_rScenario.hasAttribute(OV_AttributeId_ScenarioFilename))
|
||||
{
|
||||
const std::string filename = m_rScenario.getAttributeValue(OV_AttributeId_ScenarioFilename).toASCIIString();
|
||||
const size_t iDir = filename.rfind('/');
|
||||
if (iDir != std::string::npos) { rExpandedString = CString(filename.substr(0, iDir).c_str()); }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Expand settings from the scenario
|
||||
if (m_rScenario.hasSettingWithName(rStringToExpand))
|
||||
{
|
||||
m_rScenario.getSettingValue(rStringToExpand, rExpandedString);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CScenarioSettingKeywordParserCallback final : public IConfigurationKeywordExpandCallback
|
||||
{
|
||||
public:
|
||||
explicit CScenarioSettingKeywordParserCallback(const IScenario& scenario)
|
||||
: m_rScenario(scenario) {}
|
||||
|
||||
~CScenarioSettingKeywordParserCallback() override {}
|
||||
bool expand(const CString& rStringToExpand, CString& rExpandedString) const override;
|
||||
|
||||
private:
|
||||
const IScenario& m_rScenario;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../ovk_tools.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
template <class T>
|
||||
class TAttributable : public T
|
||||
{
|
||||
public:
|
||||
|
||||
explicit TAttributable(const IKernelContext& ctx) : T(ctx) { }
|
||||
|
||||
bool addAttribute(const CIdentifier& attributeID, const CString& sAttributeValue) override
|
||||
{
|
||||
const auto itAttribute = m_attributes.find(attributeID);
|
||||
if (itAttribute != m_attributes.end()) { return false; }
|
||||
m_attributes[attributeID] = sAttributeValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool removeAttribute(const CIdentifier& attributeID) override
|
||||
{
|
||||
const auto itAttribute = m_attributes.find(attributeID);
|
||||
if (itAttribute == m_attributes.end()) { return false; }
|
||||
m_attributes.erase(itAttribute);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool removeAllAttributes() override
|
||||
{
|
||||
m_attributes.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
CString getAttributeValue(const CIdentifier& attributeID) const override
|
||||
{
|
||||
const auto itAttribute = m_attributes.find(attributeID);
|
||||
if (itAttribute == m_attributes.end()) { return CString(""); }
|
||||
return itAttribute->second;
|
||||
}
|
||||
|
||||
bool setAttributeValue(const CIdentifier& attributeID, const CString& value) override
|
||||
{
|
||||
auto itAttribute = m_attributes.find(attributeID);
|
||||
if (itAttribute == m_attributes.end())
|
||||
{
|
||||
m_attributes[attributeID] = value;
|
||||
return true;
|
||||
}
|
||||
itAttribute->second = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasAttribute(const CIdentifier& attributeID) const override
|
||||
{
|
||||
const auto itAttribute = m_attributes.find(attributeID);
|
||||
if (itAttribute == m_attributes.end()) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasAttributes() const override { return !m_attributes.empty(); }
|
||||
|
||||
CIdentifier getNextAttributeIdentifier(const CIdentifier& previousID) const override { return getNextIdentifier<CString>(m_attributes, previousID); }
|
||||
|
||||
_IsDerivedFromClass_(T, OVK_ClassId_Kernel_Scenario_AttributableT)
|
||||
|
||||
protected:
|
||||
|
||||
std::map<CIdentifier, CString> m_attributes;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovk_defines.h"
|
||||
#include "ovk_tools.h"
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
// Global Class Identifiers
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVK_ClassId_KernelDesc OpenViBE::CIdentifier(0x02F2D050, 0x25CD9EE5)
|
||||
|
||||
// Kernel Class Identifiers
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVK_ClassId_Kernel_KernelObjectT OpenViBE::CIdentifier(0x672AE465, 0x60CB46D8)
|
||||
#define OVK_ClassId_Kernel_KernelObjectFactory OpenViBE::CIdentifier(0x7D380DFA, 0x1B33AE2F)
|
||||
#define OVK_ClassId_Kernel_KernelContext OpenViBE::CIdentifier(0x72D4050C, 0x543DDAD8)
|
||||
#define OVK_ClassId_Kernel_TypeManager OpenViBE::CIdentifier(0x11D27788, 0x0602030A)
|
||||
|
||||
#define OVK_ClassId_Kernel_Algorithm_AlgorithmProxy OpenViBE::CIdentifier(0x7C741F2F, 0x24314CFF)
|
||||
#define OVK_ClassId_Kernel_Algorithm_AlgorithmContext OpenViBE::CIdentifier(0xBE3E7F65, 0x2752D79E)
|
||||
#define OVK_ClassId_Kernel_Algorithm_AlgorithmManager OpenViBE::CIdentifier(0xA75B6AA8, 0xEE0A25A4)
|
||||
#define OVK_ClassId_Kernel_Algorithm_AlgorithmProto OpenViBE::CIdentifier(0x3C83B501, 0xD5992078)
|
||||
|
||||
#define OVK_ClassId_Kernel_Config_ConfigManager OpenViBE::CIdentifier(0xE483786B, 0xA464DD55)
|
||||
|
||||
#define OVK_ClassId_Kernel_Log_LogManager OpenViBE::CIdentifier(0x1FE5CF01, 0x0B2B3748)
|
||||
#define OVK_ClassId_Kernel_Log_LogListenerConsole OpenViBE::CIdentifier(0x1EEB056C, 0x373C17C7)
|
||||
#define OVK_ClassId_Kernel_Log_LogListenerFile OpenViBE::CIdentifier(0x6A7FCB0C, 0xC847976D)
|
||||
#define OVK_ClassId_Kernel_Log_LogListenerDebug OpenViBE::CIdentifier(0x45C1A72F, 0x647DE336)
|
||||
#define OVK_ClassId_Kernel_Log_LogListenerNull OpenViBE::CIdentifier(0x1341E7E6, 0x2232EB75)
|
||||
|
||||
#define OVK_ClassId_Kernel_Error_ErrorManager OpenViBE::CIdentifier(0xB4F8AA7C, 0x286FE5C6)
|
||||
#define OVK_ClassId_Kernel_Error_Error OpenViBE::CIdentifier(0xA52EA1C9, 0xC14FC982)
|
||||
|
||||
#define OVK_ClassId_Kernel_Plugins_PluginManager OpenViBE::CIdentifier(0x07DB32AD, 0x76FAD392)
|
||||
#define OVK_ClassId_Kernel_Plugins_PluginModule OpenViBE::CIdentifier(0x34883FDB, 0x78B6D1E6)
|
||||
#define OVK_ClassId_Kernel_Plugins_PluginModuleContext OpenViBE::CIdentifier(0x78071145, 0x308261A2)
|
||||
#define OVK_ClassId_Kernel_Plugins_PluginObject OpenViBE::CIdentifier(0x718F6C0B, 0x368B2E6C)
|
||||
#define OVK_ClassId_Kernel_Plugins_PluginObjectDesc OpenViBE::CIdentifier(0x65853ECE, 0x6E203E71)
|
||||
|
||||
#define OVK_ClassId_Kernel_Metaboxes_MetaboxManager OpenViBE::CIdentifier(0x07DB34DA, 0xF67AD392)
|
||||
#define OVK_ClassId_Kernel_Metaboxes_MetaboxObjectDesc OpenViBE::CIdentifier(0x100E6855, 0xFF905FEA)
|
||||
|
||||
#define OVK_ClassId_Kernel_Player_BoxAlgorithmContext OpenViBE::CIdentifier(0x48078FB2, 0x1897AD5A)
|
||||
#define OVK_ClassId_Kernel_Player_DynamicBoxContext OpenViBE::CIdentifier(0x18FC58E0, 0x505E97CD)
|
||||
#define OVK_ClassId_Kernel_Player_MessageT OpenViBE::CIdentifier(0x42A56E80, 0x289CBB09)
|
||||
#define OVK_ClassId_Kernel_Player_MessageClock OpenViBE::CIdentifier(0x3AA34472, 0x2B1F67CB)
|
||||
#define OVK_ClassId_Kernel_Player_Player OpenViBE::CIdentifier(0x7C8777FF, 0x52CE89C2)
|
||||
#define OVK_ClassId_Kernel_Player_PlayerContext OpenViBE::CIdentifier(0x76A544A0, 0x01F508ED)
|
||||
#define OVK_ClassId_Kernel_Player_PlayerManager OpenViBE::CIdentifier(0x4A46A96D, 0x6D4957C5)
|
||||
#define OVK_ClassId_Kernel_Player_SimulatedBox OpenViBE::CIdentifier(0x74D37E85, 0x73952B1D)
|
||||
#define OVK_ClassId_Kernel_Player_StaticBoxContext OpenViBE::CIdentifier(0x59B7AE07, 0x4A6FE704)
|
||||
#define OVK_ClassId_Kernel_Player_Scheduler OpenViBE::CIdentifier(0x39A9093F, 0x363DDB65)
|
||||
|
||||
#define OVK_ClassId_Kernel_Scenario_AttributableT OpenViBE::CIdentifier(0x6F4071A4, 0x31183474)
|
||||
#define OVK_ClassId_Kernel_Scenario_Box OpenViBE::CIdentifier(0x715A25DC, 0x5322E94C)
|
||||
#define OVK_ClassId_Kernel_Scenario_BoxUpdater OpenViBE::CIdentifier(0x65E887AD, 0x25FA9EEF)
|
||||
#define OVK_ClassId_Kernel_Scenario_Comment OpenViBE::CIdentifier(0xFD134BE1, 0x32BEC860)
|
||||
#define OVK_ClassId_Kernel_Scenario_Metadata OpenViBE::CIdentifier(0xFC6AAE55, 0x7965FA25)
|
||||
#define OVK_ClassId_Kernel_Scenario_BoxListenerContext OpenViBE::CIdentifier(0x6EBE7BA6, 0xF8C13ACA)
|
||||
#define OVK_ClassId_Kernel_Scenario_BoxProto OpenViBE::CIdentifier(0x290EDACD, 0x6D08F87D)
|
||||
#define OVK_ClassId_Kernel_Scenario_Link OpenViBE::CIdentifier(0x118EF337, 0x095F5A5E)
|
||||
|
||||
#define OVK_ClassId_Kernel_Scenario_Scenario OpenViBE::CIdentifier(0x4215A6BF, 0x6F4E5F96)
|
||||
#define OVK_ClassId_Kernel_Scenario_ScenarioManager OpenViBE::CIdentifier(0x5BB96551, 0x133303F9)
|
||||
#define OVK_ClassId_Kernel_Scenario_ScenarioExporterContext OpenViBE::CIdentifier(0x78606B83, 0x5EB11EC9)
|
||||
#define OVK_ClassId_Kernel_Scenario_ScenarioImporterContext OpenViBE::CIdentifier(0x17DC0F51, 0x795A3A7E)
|
||||
|
||||
#define OVK_ClassId_Kernel_ObjectVisitorContext OpenViBE::CIdentifier(0x7F6010A3, 0x17F4F20A)
|
||||
|
||||
// Tools Class Identifiers
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVK_ClassId_Tools_ScopeTester OpenViBE::CIdentifier(0x5978C732, 0x5903C7A2)
|
||||
#define OVK_ClassId_Tools_KernelObjectFactoryHelper OpenViBE::CIdentifier(0x6059EA7C, 0x081FDAB5)
|
||||
#define OVK_ClassId_Tools_BoxProxyT OpenViBE::CIdentifier(0x4DFDFCE4, 0x49EF078E)
|
||||
#define OVK_ClassId_Tools_BoxIOProxyT OpenViBE::CIdentifier(0x25476613, 0x331633DA)
|
||||
|
||||
#define OVK_ClassId_Kernel_Configurable OpenViBE::CIdentifier(0x1C1D34A4, 0x2EAB9FA1)
|
||||
#define OVK_ClassId_Kernel_ConfigurableT OpenViBE::CIdentifier(0x6500E672, 0x7520EB07)
|
||||
#define OVK_ClassId_Kernel_ParameterT OpenViBE::CIdentifier(0x6DF62060, 0x65A40A62)
|
||||
#define OVK_ClassId_Kernel_UIntegerParameter OpenViBE::CIdentifier(0x665A47DC, 0x650630EE)
|
||||
#define OVK_ClassId_Kernel_IntegerParameter OpenViBE::CIdentifier(0x52DA0F06, 0x45155D4F)
|
||||
#define OVK_ClassId_Kernel_EnumerationParameter OpenViBE::CIdentifier(0x1825F2CA, 0x5589B8E2)
|
||||
#define OVK_ClassId_Kernel_BooleanParameter OpenViBE::CIdentifier(0x4E79D376, 0x151D2473)
|
||||
#define OVK_ClassId_Kernel_FloatParameter OpenViBE::CIdentifier(0x37B24229, 0x6A053984)
|
||||
#define OVK_ClassId_Kernel_StringParameter OpenViBE::CIdentifier(0x4AA96293, 0x2B76B89C)
|
||||
#define OVK_ClassId_Kernel_IdentifierParameter OpenViBE::CIdentifier(0x1C4D8B4C, 0x67CFF22B)
|
||||
#define OVK_ClassId_Kernel_MatrixParameter OpenViBE::CIdentifier(0xB1C67A8B, 0xED6BD64D)
|
||||
#define OVK_ClassId_Kernel_StimulationSetParameter OpenViBE::CIdentifier(0x758D94E1, 0x40F42B99)
|
||||
#define OVK_ClassId_Kernel_MemoryBufferParameter OpenViBE::CIdentifier(0x8E21C24F, 0xD77B7E6D)
|
||||
#define OVK_ClassId_Kernel_ObjectParameter OpenViBE::CIdentifier(0x5A9CB52C, 0x7F02D159)
|
||||
#define OVK_ClassId_Kernel_PointerParameter OpenViBE::CIdentifier(0x29BDDFF0, 0x85B669E2)
|
||||
|
||||
// API Definition
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
// Taken from
|
||||
// - http://people.redhat.com/drepper/dsohowto.pdf
|
||||
// - http://www.nedprod.com/programs/gccvisibility.html
|
||||
#if defined OVK_Shared
|
||||
#if defined TARGET_OS_Windows
|
||||
#define OVK_API_Export __declspec(dllexport)
|
||||
#define OVK_API_Import __declspec(dllimport)
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
#define OVK_API_Export __attribute__((visibility("default")))
|
||||
#define OVK_API_Import __attribute__((visibility("default")))
|
||||
#else
|
||||
#define OVK_API_Export
|
||||
#define OVK_API_Import
|
||||
#endif
|
||||
#else
|
||||
#define OVK_API_Export
|
||||
#define OVK_API_Import
|
||||
#endif
|
||||
|
||||
#if defined OVK_Exports
|
||||
#define OVK_API OVK_API_Export
|
||||
#else
|
||||
#define OVK_API OVK_API_Import
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "kernel/ovkCKernelContext.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <system/ovCTime.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
class CKernelDesc final : public IKernelDesc
|
||||
{
|
||||
public:
|
||||
IKernelContext* createKernel(const CString& rApplicationName, const CString& rConfigurationFilename) override
|
||||
{
|
||||
return new CKernelContext(nullptr, rApplicationName, rConfigurationFilename);
|
||||
}
|
||||
|
||||
IKernelContext* createKernel(const IKernelContext& masterKernelCtx, const CString& applicationName, const CString& configFilename)
|
||||
override { return new CKernelContext(&masterKernelCtx, applicationName, configFilename); }
|
||||
|
||||
void releaseKernel(IKernelContext* pKernelContext) override { delete pKernelContext; }
|
||||
CString getName() const override { return "OpenViBE Kernel Implementation"; }
|
||||
CString getAuthorName() const override { return "Yann Renard"; }
|
||||
CString getAuthorCompanyName() const override { return "INRIA/IRISA"; }
|
||||
CString getShortDescription() const override { return "OpenViBE Kernel Implementation"; }
|
||||
CString getDetailedDescription() const override { return "OpenViBE Kernel Implementation"; }
|
||||
CString getVersion() const override { return "0.5"; }
|
||||
|
||||
_IsDerivedFromClass_Final_(IKernelDesc, OVK_ClassId_KernelDesc)
|
||||
};
|
||||
|
||||
static CKernelDesc gKernelDesc;
|
||||
|
||||
extern "C" {
|
||||
|
||||
OVK_API bool onInitialize() { return true; }
|
||||
OVK_API bool onUninitialize() { return true; }
|
||||
|
||||
OVK_API bool onGetKernelDesc(IKernelDesc*& rpKernelDesc)
|
||||
{
|
||||
rpKernelDesc = &gKernelDesc;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "tools/ovkCKernelObjectFactoryHelper.h"
|
||||
#include "tools/ovkCScopeTester.h"
|
||||
|
||||
#include "tools/ovk_identifier_map_iterator.h"
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Tools {
|
||||
class CKernelObjectFactoryHelper final : public IObject
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CKernelObjectFactoryHelper(Kernel::IKernelObjectFactory& rKernelObjectFactory)
|
||||
: m_rKernelObjectFactory(rKernelObjectFactory) { }
|
||||
|
||||
template <class T>
|
||||
T createObject(const CIdentifier& classID)
|
||||
{
|
||||
IObject* obj = m_rKernelObjectFactory.createObject(classID);
|
||||
T res = dynamic_cast<T>(obj);
|
||||
if (obj && !res) { m_rKernelObjectFactory.releaseObject(obj); }
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool releaseObject(T tObject) { return m_rKernelObjectFactory.releaseObject(tObject); }
|
||||
|
||||
_IsDerivedFromClass_Final_(IObject, OVK_ClassId_Tools_KernelObjectFactoryHelper)
|
||||
|
||||
protected:
|
||||
|
||||
Kernel::IKernelObjectFactory& m_rKernelObjectFactory;
|
||||
|
||||
private:
|
||||
|
||||
CKernelObjectFactoryHelper();
|
||||
};
|
||||
} // namespace Tools
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovk_base.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Tools {
|
||||
class CScopeTester final : public IObject
|
||||
{
|
||||
public:
|
||||
|
||||
CScopeTester(const Kernel::IKernelContext& ctx, const CString& prefix)
|
||||
: m_prefix(prefix), m_kernelCtx(ctx) { m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "## CScopeTester [" << m_prefix << "] enter\n"; }
|
||||
~CScopeTester() override { m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "## CScopeTester [" << m_prefix << "] leave\n"; }
|
||||
|
||||
_IsDerivedFromClass_Final_(IObject, OVK_ClassId_Tools_ScopeTester)
|
||||
|
||||
protected:
|
||||
|
||||
CString m_prefix;
|
||||
const Kernel::IKernelContext& m_kernelCtx;
|
||||
};
|
||||
} // namespace Tools
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/kernel/scenario/ovIBoxProto.h>
|
||||
#include <system/ovCMemory.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Kernel {
|
||||
|
||||
struct SBoxProto final : IBoxProto
|
||||
{
|
||||
SBoxProto(ITypeManager& typeManager) : m_TypeManager(typeManager) { }
|
||||
|
||||
bool addInput(const CString& /*name*/, const CIdentifier& typeID, const CIdentifier& id, const bool /*notify*/) override
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_inputCountHash);
|
||||
swap_byte(m_inputCountHash, 0x7936A0F3BD12D936LL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
if (id != CIdentifier::undefined())
|
||||
{
|
||||
v = id.id();
|
||||
swap_byte(v, 0x2BD1D158F340014D);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addOutput(const CString& /*name*/, const CIdentifier& typeID, const CIdentifier& id, const bool /*notify*/) override
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_outputCountHash);
|
||||
swap_byte(m_outputCountHash, 0xCBB66A5B893AA4E9LL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
if (id != CIdentifier::undefined())
|
||||
{
|
||||
v = id.id();
|
||||
swap_byte(v, 0x87CA0F5EFC4FAC68);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addSetting(const CString& /*name*/, const CIdentifier& typeID, const CString& /*defaultValue*/, const bool /*modifiable*/, const CIdentifier& id,
|
||||
const bool /*notify*/) override
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_settingCountHash);
|
||||
swap_byte(m_settingCountHash, 0x3C87F3AAE9F8303BLL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
if (id != CIdentifier::undefined())
|
||||
{
|
||||
v = id.id();
|
||||
swap_byte(v, 0x17185F7CDA63A9FA);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addInputSupport(const CIdentifier& typeID) override
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_outputCountHash);
|
||||
swap_byte(m_outputCountHash, 0xCBB66A5B893AA4E9LL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addInputAndDerivedSupport(const CIdentifier& typeID)
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_outputCountHash);
|
||||
swap_byte(m_outputCountHash, 0xCBB66A5B893AA4E9LL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addOutputSupport(const CIdentifier& typeID) override
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_outputCountHash);
|
||||
swap_byte(m_outputCountHash, 0xCBB66A5B893AA4E9LL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addOutputAndDerivedSupport(const CIdentifier& typeID)
|
||||
{
|
||||
uint64_t v = typeID.id();
|
||||
swap_byte(v, m_outputCountHash);
|
||||
swap_byte(m_outputCountHash, 0xCBB66A5B893AA4E9LL);
|
||||
m_hash = m_hash.id() ^ v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addFlag(const EBoxFlag flag) override
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case BoxFlag_CanAddInput: m_hash = m_hash.id() ^ CIdentifier(0x07507AC8, 0xEB643ACE).id();
|
||||
break;
|
||||
case BoxFlag_CanModifyInput: m_hash = m_hash.id() ^ CIdentifier(0x5C985376, 0x8D74CDB8).id();
|
||||
break;
|
||||
case BoxFlag_CanAddOutput: m_hash = m_hash.id() ^ CIdentifier(0x58DEA69B, 0x12411365).id();
|
||||
break;
|
||||
case BoxFlag_CanModifyOutput: m_hash = m_hash.id() ^ CIdentifier(0x6E162C01, 0xAC979F22).id();
|
||||
break;
|
||||
case BoxFlag_CanAddSetting: m_hash = m_hash.id() ^ CIdentifier(0xFA7A50DC, 0x2140C013).id();
|
||||
break;
|
||||
case BoxFlag_CanModifySetting: m_hash = m_hash.id() ^ CIdentifier(0x624D7661, 0xD8DDEA0A).id();
|
||||
break;
|
||||
case BoxFlag_IsDeprecated: m_isDeprecated = true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addFlag(const CIdentifier& flagId) override
|
||||
{
|
||||
const uint64_t value = m_TypeManager.getEnumerationEntryValueFromName(OV_TypeId_BoxAlgorithmFlag, flagId.toString());
|
||||
if (value == CIdentifier::undefined().id()) { return false; }
|
||||
// Flags do not modify internal hash
|
||||
//m_hash=m_hash.id() ^ flagId.id();
|
||||
return true;
|
||||
}
|
||||
|
||||
void swap_byte(uint64_t& v, const uint64_t s)
|
||||
{
|
||||
uint8_t v2[sizeof(v)];
|
||||
uint8_t s2[sizeof(s)];
|
||||
System::Memory::hostToLittleEndian(v, v2);
|
||||
System::Memory::hostToLittleEndian(s, s2);
|
||||
for (size_t i = 0; i < sizeof(s); i += 2)
|
||||
{
|
||||
const size_t j = s2[i] % sizeof(v);
|
||||
const size_t k = s2[i + 1] % sizeof(v);
|
||||
const uint8_t t = v2[j];
|
||||
v2[j] = v2[k];
|
||||
v2[k] = t;
|
||||
}
|
||||
System::Memory::littleEndianToHost(v2, &v);
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxProto, CIdentifier::undefined())
|
||||
|
||||
CIdentifier m_hash = CIdentifier::undefined();
|
||||
bool m_isDeprecated = false;
|
||||
uint64_t m_inputCountHash = 0x64AC3CB54A35888CLL;
|
||||
uint64_t m_outputCountHash = 0x21E0FAAFE5CAF1E1LL;
|
||||
uint64_t m_settingCountHash = 0x6BDFB15B54B09F63LL;
|
||||
ITypeManager& m_TypeManager;
|
||||
};
|
||||
} // namespace Kernel
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
template <class T>
|
||||
OpenViBE::CIdentifier getNextIdentifier(const std::map<OpenViBE::CIdentifier, T>& map, const OpenViBE::CIdentifier& previousID)
|
||||
{
|
||||
typename std::map<OpenViBE::CIdentifier, T>::const_iterator it;
|
||||
|
||||
if (previousID == OpenViBE::CIdentifier::undefined()) { it = map.begin(); }
|
||||
else
|
||||
{
|
||||
it = map.find(previousID);
|
||||
if (it == map.end()) { return OpenViBE::CIdentifier::undefined(); }
|
||||
++it;
|
||||
}
|
||||
|
||||
return it != map.end() ? it->first : OpenViBE::CIdentifier::undefined();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "lepton/Lepton.h"
|
||||
#include "../ovk_base.h"
|
||||
|
||||
#include <openvibe/kernel/ovITypeManager.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
|
||||
// because std::tolower has multiple signatures,
|
||||
// it can not be easily used in std::transform
|
||||
// this workaround is taken from http://www.gcek.net/ref/books/sw/cpp/ticppv2/
|
||||
template <class TCharT>
|
||||
TCharT ToLower(TCharT c) { return std::tolower(c); }
|
||||
|
||||
/**
|
||||
* \brief Check the setting value (if the setting is numeric),
|
||||
* test if it is a correct arithmetic expression, should be used after
|
||||
* retrieving the value with "getSettingValue"
|
||||
* \param value [in] : The value of setting to check
|
||||
* \param typeID [in] : The type of setting to check
|
||||
* \param typeManager [in] :
|
||||
* \return \e true in case of success (numeric value is well formed).
|
||||
* \return \e false in case of error. In such case,
|
||||
* \c value remains unchanged.
|
||||
*/
|
||||
inline bool checkSettingValue(const OpenViBE::CString& value, const OpenViBE::CIdentifier& typeID, const OpenViBE::Kernel::ITypeManager& typeManager)
|
||||
{
|
||||
if (typeManager.isEnumeration(typeID))
|
||||
{
|
||||
const auto enumerationEntryValue = typeManager.getEnumerationEntryValueFromName(typeID, value);
|
||||
const auto enumerationEntryReversedName = typeManager.getEnumerationEntryNameFromValue(typeID, enumerationEntryValue);
|
||||
// We need to compare the reversed name of the enumerations because some enumeration values actually use max int
|
||||
// which is the same value as the guard value for incorrect stimulations
|
||||
if (enumerationEntryValue == OV_IncorrectStimulation && enumerationEntryReversedName != value) { return false; }
|
||||
}
|
||||
else if (typeID == OV_TypeId_Float || typeID == OV_TypeId_Integer)
|
||||
{
|
||||
// If the token is a numeric value, it may be an arithmetic operation
|
||||
// parse and expression with no variables or functions
|
||||
try { Lepton::Parser::parse(value.toASCIIString()).evaluate(); }
|
||||
catch (...) { return false; }
|
||||
}
|
||||
else if (typeID == OV_TypeId_Boolean)
|
||||
{
|
||||
std::string val = value.toASCIIString();
|
||||
std::transform(val.begin(), val.end(), val.begin(), ::ToLower<std::string::value_type>);
|
||||
|
||||
if (!(val == "true" || val == "on" || val == "1" || val == "false" || val == "off" || val == "0")) { return false; }
|
||||
}
|
||||
//TODO: else
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user